SQL 查询过滤器以根据其他 2 列中的值在一列中查找重复项
SQL Query Filter to locate DUPLICATES in a column based on Values in 2 other columns
我正在使用 SQL Server 2014,并且正在使用名为 ReservationStay 的 table。它包含所有客人的姓名、到达日期和离开日期的记录。已进行一项操作,将数百位客人的记录拆分为 2 个单独的条目,这意味着这些条目现在具有相同的客人姓名,但到达日期和离开日期不同。
原始条目示例:
Name ArrivalDate DepartureDate
Simon G 2015-06-01 2015-06-08
下面是拆分操作生效后发生的事情,比如说,2015 年 6 月 3 日:
Name ArrivalDate DepartureDate
Simon G 2015-06-01 2015-06-03
Simon G 2015-06-03 2015-06-08
这个拆分操作进行了好几天
我的查询中需要一个过滤器,它会考虑以下因素:
WHERE 名称重复,第一个条目的出发日期 = 第二个条目的到达日期。
基本上,我想重新构建原始条目。
如何编写此过滤器?
可以用一个简单的 INNER JOIN
("self-join"):
SELECT a.Name, a.ArrivalDate, b.DepartureDate
FROM dtab a
INNER JOIN dtab b ON b.Name=a.Name
AND b.ArrivalDate=a.DepartureDate
看这里http://sqlfiddle.com/#!9/51ea3/2
我在 table 中添加了几行,以提供一个 不 满足条件的示例:
CREATE TABLE dtab (Name varchar(11),ArrivalDate varchar(10),DepartureDate varchar(10));
INSERT INTO dtab (Name,ArrivalDate,DepartureDate)
VALUES
('Simon G', '2015-06-01', '2015-06-03'),
('Simon G', '2015-06-03', '2015-06-08'),
('Peter M', '2015-03-07', '2015-03-15'),
('Peter M', '2015-05-05', '2015-05-10');
并得到想要的结果
| Name | ArrivalDate | DepartureDate |
|---------|-------------|---------------|
| Simon G | 2015-06-01 | 2015-06-08 |
编辑
刚刚注意到,为了重建未拆分的 table,您还需要列出之前 未 拆分的条目。为此,您可以执行以下操作:
WITH combined AS (
SELECT a.Name cnam, a.ArrivalDate carr, b.DepartureDate cdep
FROM dtab a
INNER JOIN dtab b ON b.Name=a.Name
AND b.ArrivalDate=a.DepartureDate
)
SELECT d.* FROM dtab d
LEFT JOIN combined ON cnam=Name AND (carr=ArrivalDate OR cdep=DepartureDate)
WHERE cdep IS NULL
UNION ALL
SELECT * FROM combined
我把原来的SELECT
语句放到一个普通的table表达式中(combined
),然后用它来检查原来的table是否到达或离开日期这些条目中的任何一个都是一致的。如果他们这样做,原始条目将 不 列出,否则它们将与 combined
table 的条目一起列在 UNION
中。 =23=]
现在我们得到
| Name | ArrivalDate | DepartureDate |
|---------|-------------|---------------|
| Peter M | 2015-03-07 | 2015-03-15 |
| Peter M | 2015-05-05 | 2015-05-10 |
| Simon G | 2015-06-01 | 2015-06-08 |
看这里http://sqlfiddle.com/#!6/7d325/5
此解决方案适用于 SQL Server 2005(LAG / LEAP
在 SQL Server 2012 中引入)。
declare @t table (name varchar(10),Arrivaldate varchar(20),Departure varchar(20))
insert into @t(name,Arrivaldate,Departure)
values
('Simon G','2015-06-01','2015-06-03'),
('Simon G','2015-06-03','2015-06-08')
Select A.name,A.Arrivaldate,A.Departure from (
select NAME,MIN(Arrivaldate)Arrivaldate,MAX(Departure)Departure from @t GROUP BY NAME)A
您可以使用 LEAD
、LAG
window 函数来定位已拆分的记录:
SELECT Name, MIN(ArrivalDate) AS ArrivalDate, MAX(DepartureDate) AS DepartureDate
FROM (
SELECT Name, ArrivalDate, DepartureDate,
CASE
WHEN ArrivalDate = LAG(DepartureDate) OVER (PARTITION BY Name
ORDER BY ArrivalDate)
OR
DepartureDate = LEAD(ArrivalDate) OVER (PARTITION BY Name
ORDER BY ArrivalDate)
THEN 1
ELSE 0
END AS HasBeenSplit
FROM mytable ) t
GROUP BY Name, HasBeenSplit
此查询将为您返回 table 的原始版本。
我正在使用 SQL Server 2014,并且正在使用名为 ReservationStay 的 table。它包含所有客人的姓名、到达日期和离开日期的记录。已进行一项操作,将数百位客人的记录拆分为 2 个单独的条目,这意味着这些条目现在具有相同的客人姓名,但到达日期和离开日期不同。
原始条目示例:
Name ArrivalDate DepartureDate
Simon G 2015-06-01 2015-06-08
下面是拆分操作生效后发生的事情,比如说,2015 年 6 月 3 日:
Name ArrivalDate DepartureDate
Simon G 2015-06-01 2015-06-03
Simon G 2015-06-03 2015-06-08
这个拆分操作进行了好几天
我的查询中需要一个过滤器,它会考虑以下因素:
WHERE 名称重复,第一个条目的出发日期 = 第二个条目的到达日期。
基本上,我想重新构建原始条目。
如何编写此过滤器?
可以用一个简单的 INNER JOIN
("self-join"):
SELECT a.Name, a.ArrivalDate, b.DepartureDate
FROM dtab a
INNER JOIN dtab b ON b.Name=a.Name
AND b.ArrivalDate=a.DepartureDate
看这里http://sqlfiddle.com/#!9/51ea3/2
我在 table 中添加了几行,以提供一个 不 满足条件的示例:
CREATE TABLE dtab (Name varchar(11),ArrivalDate varchar(10),DepartureDate varchar(10));
INSERT INTO dtab (Name,ArrivalDate,DepartureDate)
VALUES
('Simon G', '2015-06-01', '2015-06-03'),
('Simon G', '2015-06-03', '2015-06-08'),
('Peter M', '2015-03-07', '2015-03-15'),
('Peter M', '2015-05-05', '2015-05-10');
并得到想要的结果
| Name | ArrivalDate | DepartureDate |
|---------|-------------|---------------|
| Simon G | 2015-06-01 | 2015-06-08 |
编辑
刚刚注意到,为了重建未拆分的 table,您还需要列出之前 未 拆分的条目。为此,您可以执行以下操作:
WITH combined AS (
SELECT a.Name cnam, a.ArrivalDate carr, b.DepartureDate cdep
FROM dtab a
INNER JOIN dtab b ON b.Name=a.Name
AND b.ArrivalDate=a.DepartureDate
)
SELECT d.* FROM dtab d
LEFT JOIN combined ON cnam=Name AND (carr=ArrivalDate OR cdep=DepartureDate)
WHERE cdep IS NULL
UNION ALL
SELECT * FROM combined
我把原来的SELECT
语句放到一个普通的table表达式中(combined
),然后用它来检查原来的table是否到达或离开日期这些条目中的任何一个都是一致的。如果他们这样做,原始条目将 不 列出,否则它们将与 combined
table 的条目一起列在 UNION
中。 =23=]
现在我们得到
| Name | ArrivalDate | DepartureDate |
|---------|-------------|---------------|
| Peter M | 2015-03-07 | 2015-03-15 |
| Peter M | 2015-05-05 | 2015-05-10 |
| Simon G | 2015-06-01 | 2015-06-08 |
看这里http://sqlfiddle.com/#!6/7d325/5
此解决方案适用于 SQL Server 2005(LAG / LEAP
在 SQL Server 2012 中引入)。
declare @t table (name varchar(10),Arrivaldate varchar(20),Departure varchar(20))
insert into @t(name,Arrivaldate,Departure)
values
('Simon G','2015-06-01','2015-06-03'),
('Simon G','2015-06-03','2015-06-08')
Select A.name,A.Arrivaldate,A.Departure from (
select NAME,MIN(Arrivaldate)Arrivaldate,MAX(Departure)Departure from @t GROUP BY NAME)A
您可以使用 LEAD
、LAG
window 函数来定位已拆分的记录:
SELECT Name, MIN(ArrivalDate) AS ArrivalDate, MAX(DepartureDate) AS DepartureDate
FROM (
SELECT Name, ArrivalDate, DepartureDate,
CASE
WHEN ArrivalDate = LAG(DepartureDate) OVER (PARTITION BY Name
ORDER BY ArrivalDate)
OR
DepartureDate = LEAD(ArrivalDate) OVER (PARTITION BY Name
ORDER BY ArrivalDate)
THEN 1
ELSE 0
END AS HasBeenSplit
FROM mytable ) t
GROUP BY Name, HasBeenSplit
此查询将为您返回 table 的原始版本。