SELECT和WHERE子句中的Postgresql表名或别名,不指定列名

时间:2016-09-22 16:36:07

标签: postgresql

我有两张桌子:

CREATE TABLE a (id INT NOT NULL);
CREATE TABLE b (id INT NOT NULL);
INSERT INTO a VALUES (1), (2);
INSERT INTO b VALUES (1);

如果我尝试从a获取记录,b查询1 )中有记录:

SELECT a.id, b FROM a LEFT JOIN b on a.id = b.id WHERE b is NOT NULL;

我明白了:

 id |  b  
----+-----
  1 | (1)

如果我尝试从a查询2 )中没有记录的b获取记录:

SELECT a.id, b FROM a LEFT JOIN b on a.id = b.id WHERE b IS NULL;

我明白了:

 id | b 
----+---
  2 | 

似乎没问题。

然后我改变b

ALTER TABLE b ADD COLUMN s TEXT NULL;

然后查询1不返回任何行,查询2返回相同的行和

SELECT a.id, b FROM a LEFT JOIN b on a.id = b.id;

返回

 id |  b   
----+------
  1 | (1,)
  2 | 

我的问题是:

  1. 为什么Postresql允许在WHERE子句中使用表名或别名而不指定列名?
  2. 结果行的(1,)列中的b是什么?
  3. 为什么(1,)在查询1和查询2中不满足IS NULLIS NOT NULL
  4. P.S。如果我将表b改为ALTER TABLE b ADD COLUMN s TEXT NOT NULL DEFAULT '',则查询1和2会返回相同的行。

2 个答案:

答案 0 :(得分:1)

回答问题:

  1. 这是行构造函数,因此列中的每个值都使用列中其成员字段的值构建行值(复合值)
  2. (1,)是一个行构造函数,第一个成员为1,第二个成员(您的文本字段)的值为null,因此不会显示任何值。
  3. 您正在比较实际满足两个比较的整个行构造函数(null和非null)
  4. 更多关于第3点:

    select *, b is not null as b_not_null, b is null as b_null from b;
    

    Reult:

     id | b_not_null | b_null
    ----+------------+--------
      1 | t          | f
    

    IS NULL,当其所有成员都有NULL个值时,否则为IS NOT NULL。再现:

    create table rowtest ( col1 int, col2 int);
    insert into rowtest values (null,null), (1,1), (null,1);
    
    select 
      col1, col2, rowtest,
      case when rowtest is null then true else false end as rowtest_null
    from rowtest;
    

    结果:

     col1 | col2 | rowtest | rowtest_null
    ------+------+---------+--------------
          |      | (,)     | t
        1 |    1 | (1,1)   | f
          |    1 | (,1)    | f
    

    实际上,对于您的查询,它们都可以重写为:

    查询1 :从a获取来自b的匹配记录的记录

    使用与INNER JOIN实际相同的JOIN

    SELECT a.id, b FROM a JOIN b on a.id = b.id;
    

    查询2 :从a获取与b无匹配记录的记录

    使用NOT EXISTS代替LEFT JOIN

    SELECT a.id 
    FROM a 
    WHERE NOT EXISTS (
      SELECT 1 
      FROM b
      WHERE a.id = b.id
      );
    

    对于最后一个查询,如果你真的需要第二个空列,你可以添加一个静态值来选择列表:

    SELECT a.id, null as b
    

答案 1 :(得分:0)

表名可以在SELECTWHERE中使用,以引用包含表格整行的记录值。在psql的输出中,记录将显示为(1)(如果它有一个字段),或(1,2)(如果它有两个字段),等等。(1,)您会看到包含值1NULL的两个字段的记录。记录类型的值可以为null,例如如果第二个表没有匹配的行,则在左连接中。