关于同一城市中的人的有条件声明

时间:2019-03-05 20:46:51

标签: sql sql-server tsql

我有一个简化的表(myPeeps),其中有2列:城市和名称

  1. 如果在同一个城市有约翰和玛丽,我只需要为玛丽显示一行
  2. 如果在同一个城市有约翰,玛丽和史蒂夫,我只需要为约翰显示一行
  3. 如果在同一座城市有约翰和史蒂夫,请为史蒂夫表演

如果存在以上规则中未提及的其他组合,则必须显示每一行

我该怎么做?我需要额外的加入吗?还是在什么情况下使用情况?

3 个答案:

答案 0 :(得分:3)

使用STRING_AGG

WITH cte AS (
  SELECT city, STRING_AGG(name, ',') WITHIN GROUP(ORDER BY name)AS people
  FROM tab
  GROUP BY city
)
SELECT *
FROM tab t
WHERE EXISTS (SELECT 1
              FROM cte c
              WHERE t.city = c.city 
                AND CASE c.people
                       WHEN 'John,Mary' THEN 'Mary'
                       WHEN 'John,Mary,Steve' THEN 'John'
                       WHEN 'John,Steve' THEN 'Steve'
                       ELSE t.name
                    END = t.name)

db<>fiddle demo

示例:

+-----+-----------+-------+
| id  |   city    | name  |
+-----+-----------+-------+
|  1  | Montreal  | John  |
|  2  | Montreal  | Mary  |
|  3  | Berlin    | Mary  |
|  4  | Berlin    | Steve |
|  5  | Berlin    | John  |
|  6  | Tokyo     | Steve |
|  7  | Tokyo     | John  |
|  8  | Moscow    | Mary  |
|  9  | Moscow    | Steve |
+-----+-----------+-------+

-- Output:

+-----+-----------+-------+
| id  |   city    | name  |
+-----+-----------+-------+
|  2  | Montreal  | Mary  |
|  5  | Berlin    | John  |
|  6  | Tokyo     | Steve |
|  8  | Moscow    | Mary  |
|  9  | Moscow    | Steve |
+-----+-----------+-------+

答案 1 :(得分:0)

这真的很奇怪。我会计算特殊值并使用逻辑:

select t.*
from (select t.*,
             sum(case when name = 'John' then 1 else 0 end) over (partition by city) as has_john,
             sum(case when name = 'Mary' then 1 else 0 end) over (partition by city) as has_mary,
             sum(case when name = 'Steve' then 1 else 0 end) over (partition by city) as has_steve,
             sum(case when name not in ('John', 'Mary', 'Steve') then 1 else 0 end) over (partition by city) as has_others
      from t
     ) t
where (name = 'Mary' and has_john = 1 and has_mary = 1 and has_steve = 0 and has_others = 0) or
      (name = 'John' and has_john = 1 and has_mary = 1 and has_steve = 1 and has_others = 0) or
      (name = 'Steve' and has_john = 1 and has_mary = 0 and has_steve = 1 and has_others = 0) or
      (not (has_john = 1 and has_mary = 1 and has_steve = 0 or
            has_john = 1 and has_mary = 1 and has_steve = 1 or
            has_john = 1 and has_mary = 0 and has_steve = 1 
           )
      );

答案 2 :(得分:0)

对于每一行,如果名称是John,Mary或Steve,则需要弄清楚镇上还有谁,以决定是否将行过滤掉。最自然的方法是对子查询进行左联接。请注意,即使表中除了John,Mary或Steve之外的其他姓名,此解决方案也有效。

WITH cities_with_john AS  (SELECT City, Name FROM cities WHERE Name = 'John'),
     cities_with_Mary AS  (SELECT City, Name FROM cities WHERE Name = 'Mary'),
     cities_with_Steve AS (SELECT City, Name FROM cities WHERE Name = 'Steve')
SELECT c.*
FROM cities c
LEFT JOIN cities_with_John j ON c.City = j.City
LEFT JOIN cities_with_Mary m ON c.City = m.City
LEFT JOIN cities_with_Steve s ON c.City = s.City
WHERE c.Name NOT IN ('John', 'Mary', 'Steve') --Anyone else shows up always
    OR (c.Name = 'Mary' --Mary only shows up if either John or Steve are not in town
        AND (j.Name IS NULL OR s.Name IS NULL))
    OR (c.Name = 'Steve' --Steve only shows up if either Mary or Steve are not in town
        AND (j.Name IS NULL OR m.Name IS NULL))
    OR (c.Name = 'John' --John only shows up if both Mary and Steve are in town, or if both are not
        AND ((s.Name IS NULL AND m.Name IS NULL)
              OR (s.Name IS NOT NULL AND m.Name IS NOT NULL)))
ORDER BY City, Name

请参阅此数据集的结果,我确定了8个测试用例。在每种情况下,我还为控件添加了第四个名称(凯特):

City        Name
----------- ------------
Berlin      Kate
Havana      John
Havana      Kate
Havana      Steve
Miami       John
Miami       Kate
Miami       Mary
Miami       Steve
Nairobi     Kate
Nairobi     Mary
New York    John
New York    Kate
New York    Mary
Oslo        John
Oslo        Kate
Paris       Kate
Paris       Mary
Paris       Steve
Tokio       Kate
Tokio       Steve

测试用例是:
纽约-约翰和玛丽在市区(应该过滤掉约翰)
迈阿密-所有这些人都在城市中(应该过滤掉史蒂夫和玛丽)
哈瓦那-约翰和史蒂夫在城里(应该过滤掉约翰)
巴黎-玛丽和史蒂夫在城里(应该向所有人展示)
柏林-他们都不在这个城市(应该向所有人展示)
奥斯陆,东京,内罗毕-城市中只有一个(应该向所有人展示)

这是结果:

City         Name
------------ ----------
Berlin       Kate
Havana       Kate
Havana       Steve
Miami        John
Miami        Kate
Nairobi      Kate
Nairobi      Mary
New York     Kate
New York     Mary
Oslo         John
Oslo         Kate
Paris        Kate
Paris        Mary
Paris        Steve
Tokio        Kate
Tokio        Steve