当且仅当兄弟行不存在时返回一行

时间:2012-05-28 15:29:16

标签: sql

我今天有一个白痴日。我相信这是相对简单的,但我的大脑并没有给我答案。

我有一个表,其行是对象的类型。看起来像这样:

id    name    foo    bar    house_id
1     Cat     12     4      1
2     Cat     9      4      2
3     Dog     8      23     1
4     Bird    9      54     1
5     Bird    78     2      2
6     Bird    29     32     3

这不是我选择实施它的方式,但这正是我正在使用的方式。物品(猫,狗和鸟,在现实生活中它们是真正的商业用品)已被临时添加到表中。当house_id 1中需要猫时,猫的记录会被放入。当house_id 3获取狗时,会记录下狗的记录。

我现在需要更新此表,以便每个类型的对象(Cat,Dog,Bird)都有给定house_id的记录。我想通过插入select查询的结果来执行此操作,该查询返回每种类型的单个记录,当前和仅当没有现有记录时,来自该类型行的'foo'和'bar'的最早值对于具有给定house_id的那种类型。

因此对于上面的示例数据,给定的house_id = 3,select查询将返回以下内容:

name    foo    bar    house_id
Cat     12     4      3
Dog     8      23     3

然后我可以直接插入表格。

基本上,如果给定的house_id没有该名称的行,则返回每个不同名称的第一行。

欢迎提出建议。如果有帮助,数据库引擎就是postgres。

2 个答案:

答案 0 :(得分:2)

SET search_path= 'tmp';

DROP TABLE dogcat CASCADE;
CREATE TABLE dogcat
        ( id serial NOT NULL
        , zname    varchar
        , foo    INTEGER
        , bar    INTEGER
        , house_id INTEGER NOT NULL
        , PRIMARY KEY (zname,house_id)
        );
INSERT INTO dogcat(zname,foo,bar,house_id) VALUES
  ('Cat',12,4,1)
 ,('Cat',9,4,2)
 ,('Dog',8,23,1)
 ,('Bird',9,54,1)
 ,('Bird',78,2,2)
 ,('Bird',29,32,3)
        ;
-- Carthesian product of the {name,house_id} domains
WITH cart AS (
        WITH beast AS (
                SELECT distinct zname AS zname
                FROM dogcat
                )
        , house AS (
                SELECT distinct house_id AS house_id
                FROM dogcat
                )
        SELECT beast.zname AS zname
        ,house.house_id AS house_id
        FROM beast , house
        )
INSERT INTO dogcat(zname,house_id, foo,bar)
SELECT ca.zname, ca.house_id
        ,fb.foo, fb.bar
FROM cart ca
     -- find the animal with the lowes id
JOIN dogcat fb ON fb.zname = ca.zname AND NOT EXISTS
        ( SELECT * FROM dogcat nx
        WHERE nx.zname = fb.zname
        AND nx.id < fb.id
        )
WHERE NOT EXISTS (
        SELECT * FROM dogcat dc
        WHERE dc.zname = ca.zname
        AND dc.house_id = ca.house_id
        )
        ;

SELECT * FROM dogcat;

结果:

SET
DROP TABLE
NOTICE:  CREATE TABLE will create implicit sequence "dogcat_id_seq" for serial column "dogcat.id"
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "dogcat_pkey" for table "dogcat"
CREATE TABLE
INSERT 0 6
INSERT 0 3
 id | zname | foo | bar | house_id 
----+-------+-----+-----+----------
  1 | Cat   |  12 |   4 |        1
  2 | Cat   |   9 |   4 |        2
  3 | Dog   |   8 |  23 |        1
  4 | Bird  |   9 |  54 |        1
  5 | Bird  |  78 |   2 |        2
  6 | Bird  |  29 |  32 |        3
  7 | Cat   |  12 |   4 |        3
  8 | Dog   |   8 |  23 |        2
  9 | Dog   |   8 |  23 |        3
(9 rows)

答案 1 :(得分:0)

通常情况下,我整个上午都在努力解决问题,将其发布到Stack Overflow并在接下来的半小时内自行解决

 select name, foo, bar, 3
 from table
 where id in
 (
    select min(id) from table where name not in
    (
       select name from table where house_id = 3
    )
    group by name
 );