我有三个查询,每个查询返回一列。
SELECT Name FROM Tenant
SELECT Name FROM Space
SELECT ID FROM Contracts
表定义是:
Tenant (ID, Name)
Space (ID, Name, TenantID)
Contracts (ID, TenantID)
我在这些表格中的信息是:
+----+---------+
| id | name |
+----+---------+
| 1 | Tenant1 |
| 2 | Tenant2 |
| 3 | Tenant3 |
+----+---------+
+----+------+----------+
| id | name | tenantID |
+----+------+----------+
| 1 | S1 | 1 |
| 2 | S2 | 1 |
| 3 | S3 | 2 |
| 4 | S4 | 3 |
| 5 | S5 | 3 |
+----+------+----------+
+----+----------+
| id | tenantID |
+----+----------+
| 1 | 1 |
| 2 | 1 |
| 3 | 2 |
| 4 | 2 |
| 5 | 2 |
| 6 | 3 |
+----+----------+
如何编写查询以实现以下结构?
+----------+-------+----------+
| tenant | space | contract |
+----------+-------+----------+
| tenant 1 | S1 | 1 |
| | S2 | 2 |
| tenant 2 | S3 | 3 |
| | | 4 |
| | | 5 |
| tenant 3 | S4 | 6 |
| | S5 | |
+----------+-------+----------+
我在Tenant和Contracts表之间有链接,但我不希望他们考虑租户之间的空格,我不希望任何列中的值重复。
我尝试过使用连接,但如果它们之间存在匹配,它们显然会复制列中的值。
SELECT T.NAME 'Tname',
S.NAME 'Sname',
C.ID
FROM Tenant T
LEFT JOIN Space S
ON T.ID = S.TenantID
LEFT JOIN Contracts C
ON T.ID = C.TenantID
我也尝试将其关联到子查询中并使用ROW_NUMBER()
并结合一些CASE
语句来实现所需的格式,但不是很成功。
以下是包含一些示例数据的SQLFiddle。
非常感谢任何有用的建议/意见或链接。
答案 0 :(得分:4)
WITH SpaceRow AS (
SELECT tenantid
,name
,ROW_NUMBER() OVER (PARTITION BY tenantid ORDER BY id) AS RowNumber
FROM Space
)
,ContractRow AS (
SELECT tenantid
,id
,ROW_NUMBER() OVER (PARTITION BY tenantid ORDER BY id) AS RowNumber
FROM Contracts
)
,SpaceContracts AS (
SELECT COALESCE(SpaceRow.tenantid, ContractRow.tenantid) AS tenantid
,COALESCE(SpaceRow.RowNumber, ContractRow.RowNumber) AS RowNumber
,SpaceRow.name AS SpaceName
,ContractRow.id AS ContractId
FROM SpaceRow
FULL OUTER JOIN ContractRow
ON SpaceRow.tenantid = ContractRow.tenantid
AND SpaceRow.RowNumber = ContractRow.RowNumber
)
SELECT CASE WHEN SpaceContracts.RowNumber IS NULL
OR SpaceContracts.RowNumber = 1
THEN Tenant.name
ELSE NULL
END AS TenantName
,SpaceContracts.SpaceName
,SpaceContracts.ContractId
FROM Tenant
LEFT JOIN SpaceContracts
ON SpaceContracts.tenantid = Tenant.id
ORDER BY Tenant.id
,SpaceContracts.RowNumber
答案 1 :(得分:2)
嗯,这可能是解决问题的方法之一:
; WITH spaces AS (
SELECT t.ID AS tID, t.NAME AS tName, s.NAME AS sName, ROW_NUMBER() OVER (PARTITION BY t.ID ORDER BY s.ID) AS sSeq
FROM tenant t
LEFT JOIN space s ON t.ID = s.TenantID ),
contrs AS (
SELECT t.ID AS tID, t.NAME AS tName, c.ID AS cID, ROW_NUMBER() OVER (PARTITION BY t.ID ORDER BY c.Id) AS tSeq
FROM tenant t
LEFT JOIN contracts c ON t.ID = c.TenantID ),
partial AS (
SELECT s.tName AS tName, s.sName AS sName, c.cID As cID
FROM spaces s
LEFT JOIN contrs c ON s.tID = c.tID AND s.sSeq = c.tSeq )
SELECT (SELECT NAME FROM tenant WHERE tenant.ID = c.TenantID) AS tName, NULL AS sName, c.ID AS cID
FROM contracts c
WHERE c.ID NOT IN (SELECT cID FROM partial WHERE cID IS NOT NULL)
UNION ALL
SELECT *
FROM partial
ORDER By tName
上述基于CTE的查询产生以下输出:
tName sName cID
--------------------
Tenant1 S1 1
Tenant1 S2 2
Tenant2 S3 3
Tenant2 NULL 4
Tenant2 NULL 5
Tenant3 S4 6
Tenant3 S5 NULL
足够接近所需的输出。
答案 2 :(得分:0)
你确定这是你想要做的吗?显示所有结果(包括应该在您想要的空间中的数据)会提供更多信息。通过删除字段只是因为它在上面的字段中显示了该值,您就限制了人们可能想要进一步做的任何过滤。
另外,根据您提供的数据,您的结果是错误的,例如租户1将有4个记录而不是2.他们有2个空格和2个合同,空格和合同之间没有直接连接,这意味着您将有2x2 =租户的4条记录1.总而言之,您的输出应该有9条记录,而不是7.在给定当前结构的情况下,您无法更改此记录。
如果经理要求报告中的数据如此呈现,我建议向他们解释这种格式不太有用,如果包含所有内容,他们可以用它做更多事情。例如,如果他们想在Excel中看到它,他们如何将它过滤到Tenant 1的所有内容?在请求的格式中,如果在Tenant 1上放置过滤器,则只能看到一条记录。或者如果在csv中使用过滤器,则会加载不正确的数据。除了美观之外,除了功能之外,你想要它的布局没有任何优势。