我正在使用SQL Server 2014,我遇到了查询问题。我有三张桌子。 Report
由ClothingObservation
和HygieneObservation
各10个组成。我这样做的方法是在两种类型的观察中分别引用10行ReportId
Report
,每个报告总共20次观察。我想选择一个报告的所有行。当我尝试这样做时,我得到100行。我的目标是获得10行或20行NULL
值。这仅用于测试目的,因此Report
仅包含1行,ClothingObservation
和HygieneObservation
各包含10行,所有行都引用现有报告的ReportId
我的表格,为清晰起见省略了详细信息:
CREATE TABLE HygieneObservation
(
HygieneObservationId int PRIMARY KEY IDENTITY NOT NULL,
...
ReportId int NOT NULL
)
CREATE TABLE ClothingObservation
(
ClothingObservationId int PRIMARY KEY IDENTITY NOT NULL,
...
ReportId int NOT NULL
)
CREATE TABLE Report
(
ReportId int PRIMARY KEY IDENTITY NOT NULL,
Period Date NOT NULL,
Reporter nvarchar(8) NOT NULL,
DepartmentId int NOT NULL
)
我的查询:
SELECT
Report.ReportId,
Report.Period,
Report.Reporter,
Report.DepartmentId,
ClothingObservation.ClothingObservationId,
HygieneObservation.HygieneObservationId
FROM Report
LEFT JOIN ClothingObservation ON
(ClothingObservation.ReportId = Report.ReportId)
LEFT JOIN HygieneObservation ON
(HygieneObservation.ReportId = Report.ReportId)
GROUP BY
Report.ReportId,
Period,
Reporter,
DepartmentId,
ClothingObservation.ClothingObservationId,
HygieneObservation.HygieneObservationId
这给了我100行,据我所知,因为ClothingObservation
中的每一行都匹配HygieneObservation
中的每一行。我认为使用GROUP BY
会导致重复删除,但我显然做错了。任何提示?
编辑:这是我现在的数据(详情略去)。
Report:
ReportId Period Reporter DepartmentId
----------- ---------- -------- ------------
1 2016-05-01 username 1
ClothingObservation:
ClothingObservationId ... ReportId
--------------------- ... -----------
1 ... 1
2 ... 1
3 ... 1
4 ... 1
5 ... 1
6 ... 1
7 ... 1
8 ... 1
9 ... 1
10 ... 1
HygieneObservation:
HygieneObservationId ... ReportId
-------------------- ... -----------
3 ... 1
4 ... 1
5 ... 1
6 ... 1
7 ... 1
8 ... 1
9 ... 1
10 ... 1
12 ... 1
13 ... 1
编辑2:如果我运行这两个查询,我得到了我想要的输出(再次,从结果中省略了不相关的细节):
SELECT * FROM Report
LEFT JOIN ClothingObservation ON
(ClothingObservation.ReportId = Report.ReportId)
SELECT * FROM Report
LEFT JOIN HygieneObservation ON
(HygieneObservation.ReportId = Report.ReportId)
ReportId Period Reporter DepartmentId ClothingObservationId ... ReportId
----------- ---------- -------- ------------ --------------------- ...- -----------
1 2016-05-01 username 1 1 ... 1
1 2016-05-01 username 1 2 ... 1
1 2016-05-01 username 1 3 ... 1
1 2016-05-01 username 1 4 ... 1
1 2016-05-01 username 1 5 ... 1
1 2016-05-01 username 1 6 ... 1
1 2016-05-01 username 1 7 ... 1
1 2016-05-01 username 1 8 ... 1
1 2016-05-01 username 1 9 ... 1
1 2016-05-01 username 1 10 ... 1
ReportId Period Reporter DepartmentId HygieneObservationId ... ReportId
----------- ---------- -------- ------------ -------------------- ... -----------
1 2016-05-01 username 1 3 ... 1
1 2016-05-01 username 1 4 ... 1
1 2016-05-01 username 1 5 ... 1
1 2016-05-01 username 1 6 ... 1
1 2016-05-01 username 1 7 ... 1
1 2016-05-01 username 1 8 ... 1
1 2016-05-01 username 1 9 ... 1
1 2016-05-01 username 1 10 ... 1
1 2016-05-01 username 1 12 ... 1
1 2016-05-01 username 1 13 ... 1
我的目标是通过一个查询获得此输出(或类似的内容)。
答案 0 :(得分:2)
您也可以尝试使用以下查询:
SELECT
ReportId = ISNULL(v1.ReportId, v2.ReportId),
Period = ISNULL(v1.Period, v2.Period),
Reporter = ISNULL(v1.Reporter, v2.Reporter),
DepartmentId = ISNULL(v1.DepartmentId, v2.DepartmentId),
v1.ClothingObservationId,
v2.HygieneObservationId
FROM
(
SELECT
RowNumber = ROW_NUMBER() OVER(Partition BY r.ReportId ORDER BY c.ClothingObservationId),
r.ReportId,
r.Period,
r.Reporter,
r.DepartmentId,
c.ClothingObservationId
FROM
Report r
LEFT JOIN ClothingObservation c ON c.ReportId = r.ReportId) v1
FULL JOIN
(
SELECT
RowNumber = ROW_NUMBER() OVER(Partition BY r.ReportId ORDER BY h.HygieneObservationId),
r.ReportId,
r.Period,
r.Reporter,
r.DepartmentId,
h.HygieneObservationId
FROM Report r
LEFT JOIN HygieneObservation h ON h.ReportId = r.ReportId) v2 ON v1.RowNumber = v2.RowNumber AND v1.ReportId = v2.ReportId
ORDER BY ReportId
答案 1 :(得分:1)
正在发生的事情是,将报告(1行)加入到ClothingObservation(10行)会产生10行(1 x 10),然后加入HygieneObservation(10行),这样就可以得到100.这种情况发生的原因是因为在初始连接之后,您有10行具有相同的ReportID,因此下一个连接将获取这10行中的每一行并连接到HygieneObservation中的10行。
SELECT
Report.ReportId,
Report.Period,
Report.Reporter,
Report.DepartmentId,
ClothingObservation.ClothingObservationId,
NULL AS HygieneObservationId
FROM Report
LEFT JOIN ClothingObservation ON
(ClothingObservation.ReportId = Report.ReportId)
UNION ALL
SELECT
Report.ReportId,
Report.Period,
Report.Reporter,
Report.DepartmentId,
NULL AS ClothingObservationId,
HygieneObservation.HygieneObservationId
FROM Report
LEFT JOIN HygieneObservation ON
(HygieneObservation.ReportId = Report.ReportId)
工作原理:
你基本上写了两个单独的查询:一个连接Report和ClothingObservation,另一个连接Report到HygieneObservation。然后,将两个查询与UNION ALL
组合在一起。
这很复杂,因为它涉及我称之为“垂直合并”或“合并加入”。以下是查询(更新:我已对其进行了测试)。
SELECT
Report.ReportId,
Report.Period,
Report.Reporter,
Report.DepartmentId,
MergedObservations.ClothingObservationId,
MergedObservations.HygieneObservationId
FROM Report
LEFT JOIN
( SELECT COALESCE( ClothingObservation.ReportID, HygieneObservation.ReportID ) AS ReportID,
HygieneObservationID, ClothingObservationID -- Add appropriate columns
FROM
( SELECT ROW_NUMBER() OVER( PARTITION BY ReportID ORDER BY ClothingObservationID ) AS ResultID, ReportID, ClothingObservationID
FROM ClothingObservation ) AS ClothingObservation
FULL OUTER JOIN
( SELECT ROW_NUMBER() OVER( PARTITION BY ReportID ORDER BY HygieneObservationID ) AS ResultID, ReportID, HygieneObservationID
FROM HygieneObservation ) AS HygieneObservation
ON ClothingObservation.ReportID = HygieneObservation.ReportID
AND ClothingObservation.ResultID = HygieneObservation.ResultID
) AS MergedObservations
ON Report.ReportID = MergedObservations.ReportID
工作原理:
因为ClothingObservation和HygieneObservationId彼此不直接相关并且每个ReportID具有不同的行数,所以我使用ROW_NUMBER()
函数来生成连接键。然后,我使用ReportID和ROW_NUMBER()
函数的输出进行“合并连接”。
我已将您的示例数据转换为可用的表数据,以测试上述查询。
CREATE TABLE Report( ReportId INT, Period DATETIME, Reporter VARCHAR( 20 ), DepartmentId INT )
CREATE TABLE ClothingObservation( ClothingObservationID INT, ReportId INT )
CREATE TABLE HygieneObservation( HygieneObservationID INT, ReportId INT )
INSERT INTO Report
VALUES( 1, '2016-05-01', 'username', 1 )
INSERT INTO ClothingObservation
VALUES
( 1, 1 ), ( 2, 1 ), ( 3, 1 ), ( 4, 1 ), ( 5, 1 ), ( 6, 1 ), ( 7, 1 ), ( 8, 1 ), ( 9, 1 ), ( 10, 1 )
INSERT INTO HygieneObservation
VALUES
( 3, 1 ), ( 4, 1 ), ( 5, 1 ), ( 6, 1 ), ( 7, 1 ), ( 8, 1 ), ( 9, 1 ), ( 10, 1 ), ( 11, 1 ), ( 12, 1 ), ( 13, 1 )