SQL - 如何连接两个基于位条件的表,并始终填充字段

时间:2017-12-06 21:09:04

标签: sql sql-server

我正在尝试在MS SQL Server中连接两个表 一个表包含人名和他们的ID。

+----+---------+--------------+---------+
| ID |  Name   |    phone     |  email  |
+----+---------+--------------+---------+
|  1 | John A. | 111-111-1111 | a@email |
|  2 | Sara B. | 111-111-1112 | b@email |
|  3 | Joe C.  | 111-111-1113 | c@email |
|  4 | Jane D. | 111-111-1114 | d@email |
+----+---------+--------------+---------+

另一个表包含ID,他们知道的语言,以及指示它是否是他们的母语的位。

+----+----------+---------+
| ID | Language | Native  |
+----+----------+---------+
|  1 | English  | True    |
|  1 | Spanish  | False   |
|  2 | Spanish  | True    |
|  2 | English  | False   |
|  2 | French   | False   |
|  3 | French   | False   |
|  3 | Spanish  | False   |
|  4 | English  | True    |
+----+----------+---------+

我想要的表格应该显示身份证,人名,母语或首先返回的语言,如果这是他们的母语,电话号码,电子邮件。

+----+---------+----------+--------+--------------+---------+
| ID |  Name   | Language | Native |    phone     |  email  |
+----+---------+----------+--------+--------------+---------+
|  1 | John A. | English  | True   | 111-111-1111 | a@email |
|  2 | Sara B. | Spanish  | True   | 111-111-1112 | b@email |
|  3 | Joe C.  | French   | False  | 111-111-1113 | c@email |
|  4 | Jane D. | English  | True   | 111-111-1114 | d@email |
+----+---------+----------+--------+--------------+---------+

我尝试过加入表并提供where条件,但它只返回本地语言或该人知道的所有语言。我还尝试按ID分组,该ID表示所选列表中的列无效。我将所有列都放入group by子句中,但这给了我操作数数据类型位对于max运算符无效。

SELECT p.ID
      ,p.Name
      ,l.Language
      ,coalesce(max(l.native),0) as native
      ,p.phone
      ,p.email
  FROM people as p
  JOIN Languages as l on p.ID = l.ID
  group by p.id

3 个答案:

答案 0 :(得分:0)

SQL Server解决方案:

create table person (
    id int,
    name varchar (45),
    phone varchar (45),
    email varchar (45)
    );
create table languages (
    id int,
    language varchar (45),
    Native bit
    );
insert into person values    
(1, 'John A.', '111-111-1111', 'a@email'),
(2, 'Sara B.', '111-111-1112', 'b@email'),
(3, 'Joe C.', '111-111-1113', 'c@email'),
(4, 'Jane D.', '111-111-1114', 'd@email');
insert into languages values
(1, 'English', 1 ),
(1, 'Spanish', 0),
(2, 'Spanish', 1 ),
(2, 'English', 0),
(2, 'French', 0),
(3, 'French', 0),
(3, 'Spanish', 0),
(4, 'English', 1 );

select t1.id, t1.name, t2.language, t2.native, t1.phone, t1.email
from person t1 inner join 
(select *, row_number () over (partition by id order by id) rn
 from languages) t2 on t1.id = t2.id
 where t2.rn =1

结果:

+----+---------+----------+--------+--------------+---------+
| id |  name   | language | native |    phone     |  email  |
+----+---------+----------+--------+--------------+---------+
|  1 | John A. | English  | True   | 111-111-1111 | a@email |
|  2 | Sara B. | Spanish  | True   | 111-111-1112 | b@email |
|  3 | Joe C.  | French   | False  | 111-111-1113 | c@email |
|  4 | Jane D. | English  | True   | 111-111-1114 | d@email |
+----+---------+----------+--------+--------------+---------+

答案 1 :(得分:0)

如果你的RDBMS不支持窗口函数,那么这样的东西应该可以工作:

SELECT p.ID
      ,p.Name
      ,COALESCE(l.Language, l2.language) as language
      ,coalesce(l.native, l2.native) as native
      ,p.phone
      ,p.email
  FROM people as p
  LEFT OUTER JOIN Languages as l on p.ID = l.ID
    AND (l.native = 'true')
  LEFT OUTER JOIN (SELECT id, max(Language), native FROM Languages WHERE native = 'false' GROUP BY id, native) as l2 on p.ID = l2.ID
    AND ()
  group by p.id

答案 2 :(得分:0)

有几种方法可以做到这一点。你没有说你正在使用什么DBMS,所以我认为MySQL是最常见的开源产品。

您可以使用包含LIMIT 1子句的子查询(SQL Server中的TOP 1,但可能在子查询中不起作用)来执行此操作。

如果某人没有列出任何语言,您应该使用OUTER联接。 ORDER BY和LIMIT按字母顺序选择母语或第一语言。注意,没有真正的“第一”语言,SQL没有记录顺序,所以你需要使用ORDER BY来赋予“第一”的含义。

SELECT  p.ID,
        p.Name,
        p.phone,
        p.email,
        l.Language,
        l.Native
FROM    people as p,
LEFT OUTER JOIN
        (SELECT ID, Language, Native
         FROM Languages
         ORDER BY CASE WHEN Native THEN 0 ELSE 1 END, Language
        LIMIT 1) as l
ON      p.ID = l.ID

我没有测试过这个,但方法是正确的。如果它有问题请告诉我,我会更新语法。