组合按列分组的结果

Combine results of grouped-by columns

Consider table A:

Status                Person
------                ------
Married               Andy
Married               Bob
Married               Carol
Has Kids              Bob
Has Kids              Carol

Consider table B:

Married & Has Kids    Bob
Married & Has Kids    Carol

我可以得到table A,我可以得到table B,但是我如何同时显示A和B?我是 SQL 的新手,所以我对 UNION 的概念很模糊,那会是最好的方法吗?

编辑:

所以,我有点撒谎了。我不能准确地得到 table B,但类似:

Married               Bob
Has Kids              Bob
Married               Carol
Has Kids              Carol

我正在使用 SQL Server 2012。这是我对 table A 的查询:

SELECT Status,Person
FROM Records
WHERE Status IN ('Married', 'Has Kids')
GROUP BY Status,Person
ORDER BY Status,Person

查询 table B-ish:

SELECT Status,Person
FROM Records
WHERE Status='Married' AND Status='Has Kids'
GROUP BY Status,Person
ORDER BY Status,Person

想要一个table这样的:

Status                Person
------                ------
Married               Andy
Married               Bob
Married               Carol
Has Kids              Bob
Has Kids              Carol
Married & Has Kids    Bob
Married & Has Kids    Carol

取决于"together"的意思。

如果你想查询到return 7行,即。 table A "concatenated" 的 5 行和 table B 的 2 行,然后 UNION 正是您所需要的。

或者,如果您希望查询 return 5 行 3 列,例如Person,A的Status,B的Status,那么一个JOIN就是你所需要的。

首先,联盟。默认情况下,UNION 将消除重复记录。如果你想要重复记录 returned,或者如果你知道不能有重复记录,那么你应该使用 UNION ALL:

SELECT Status, Person FROM A
UNION ALL
SELECT Status, Person FROM B

Status                Person
------                ------
Married               Andy
Married               Bob
Married               Carol
Has Kids              Bob
Has Kids              Carol
Married & Has Kids    Bob
Married & Has Kids    Carol

对于 JOIN,您可以选择 JOINLEFT JOINRIGHT JOINFULL JOIN。第一个也称为 INNER JOIN ,其他 3 个称为外部连接,例如LEFT OUTER JOIN。就个人而言,我从不使用多余的 INNER/OUTER 关键字。

联接有一个联接条件,在您的情况下是按人员联接 table A 和 B。内部联接将仅 return 记录人员同时存在于 A 和 B 中的位置,而外部联接将 return 来自 table (LEFT/RIGHT) 或两者的所有记录 tables(满)。所有可能的组合都将被 returned,例如如果 table A 和 table B 都有 3 条关于 X 的记录,那么查询将 return 编辑 9 行。

对于下面的示例,我假设 table B 也有 Dan 的记录,以说明差异。

内部联接:

SELECT A.Person, A.Status AS StatusA, B.Status AS StatusB
  FROM A
  JOIN B ON B.Person = A.Person

Person    StatusA     StatusB
------    -------     -------
Bob       Married     Married & Has Kids
Carol     Married     Married & Has Kids
Bob       Has Kids    Married & Has Kids
Carol     Has Kids    Married & Has Kids

左外连接:

SELECT A.Person, A.Status AS StatusA, B.Status AS StatusB
  FROM A
  LEFT JOIN B ON B.Person = A.Person

Person    StatusA     StatusB
------    -------     -------
Andy      Married
Bob       Married     Married & Has Kids
Carol     Married     Married & Has Kids
Bob       Has Kids    Married & Has Kids
Carol     Has Kids    Married & Has Kids

右外连接:

SELECT B.Person, A.Status AS StatusA, B.Status AS StatusB
  FROM A
  RIGHT JOIN B ON B.Person = A.Person

Person    StatusA     StatusB
------    -------     -------
Bob       Married     Married & Has Kids
Carol     Married     Married & Has Kids
Bob       Has Kids    Married & Has Kids
Carol     Has Kids    Married & Has Kids
Dan                   Married & Has Kids

完全外部联接:

SELECT A.Person AS PersonA, A.Status AS StatusA
     , B.Person AS PersonB, B.Status AS StatusB
  FROM A
  JOIN B ON B.Person = A.Person

PersonA    StatusA     PersonB    StatusB
-------    -------     -------    -------
Andy       Married
Bob        Married     Bob        Married & Has Kids
Carol      Married     Carol      Married & Has Kids
Bob        Has Kids    Bob        Married & Has Kids
Carol      Has Kids    Carol      Married & Has Kids
                       Dan        Married & Has Kids

注意:请记住,除非用 ORDER BY 子句明确指定,否则 SQL 不保证顺序,因此上面显示的行可能 return 以不同的顺序排列。

一种方法是使用自连接并将状态连接在一起:

select status, person from a
union all
select concat(married.status, ' & ', kids.status) status, kids.person
from a kids 
join a married on kids.Person = married.Person
where kids.Status = 'Has Kids' and married.Status = 'Married'

这将为您提供示例中的准确输出。

Sample SQL Fiddle

或者您可以按照建议使用 for xml path 的相关子查询:

SELECT Status, Person FROM A 
UNION ALL
SELECT Status = LTRIM(STUFF((
          SELECT '& ' + a.Status
          FROM a 
          WHERE a.Person = a1.Person
          FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, ''))
        , person 
FROM A A1 GROUP BY Person HAVING COUNT(Status) = 2