使用多对多关系显示 table 1 中的所有记录 - postgresql
show all records in table 1 using many to many relations - postgresql
我正在尝试创建一个联系人报告,显示所有联系人和 select 在场的人。
存在存储在多对多table中。文档 ID 和出席者。
table如下:
CREATE TABLE pe
(peid int4, peco int4, pename varchar(30));
INSERT INTO pe
(peid, peco, pename)
VALUES
(1, 1,'Carl'),
(2, 1,'John'),
(3, 1,'Eric'),
(4, 2,'Donald')
;
CREATE TABLE co
(coid int, coname varchar(30));
INSERT INTO co
(coid, coname)
VALUES
(1,'Volvo'),
(2,'BMW'),
(3,'Microsoft'),
(4,'Apple')
;
There is a also a doc table that is not needed for this query
CREATE TABLE pres
(presid int4, presdoc int4, prespe int4);
INSERT INTO pres
(presid, presdoc, prespe)
VALUES
(1,1,1),
(2,2,2),
(3,2,3),
(4,3,1)
;
无效的查询(无论连接类型如何):
SELECT pename,coname,presdoc AS present
FROM pe
LEFT JOIN co ON coid=peco
LEFT JOIN pres ON prespe=peid
WHERE peco = 1 AND presdoc=2
这个查询的输出是
John Volvo present
Eric Volvo present
期望的输出是
Carl Volvo
John Volvo present
Eric Volvo present
SQLFiddle:
http://sqlfiddle.com/#!15/77b09/21
提前感谢您提供任何线索。
我认为问题出在条件 presdoc=2
上,它强制 return 只有存在的记录。这就是你需要的。
SELECT pename,
coname,
CASE
WHEN presdoc=2 THEN 'Present'
ELSE NULL
END AS Present
FROM pe
LEFT JOIN co ON coid=peco
LEFT JOIN pres ON prespe=peid
WHERE peco = 1
GROUP BY pename,
coname,
present
你能像这样执行吗(如果你只需要检查是否存在)
SELECT pename,coname,presdoc = 2 AS present
FROM pe
LEFT JOIN co ON coid=peco
LEFT JOIN pres ON prespe=peid
WHERE peco = 1
甚至更好
SELECT DISTINCT pename,coname,presdoc = 2 AS present
FROM pe
LEFT JOIN co ON coid=peco
LEFT JOIN pres ON prespe=peid
WHERE peco = 1
如果您只想检查您的文件是否已签发。然后另外你可以为你的布尔检查创建自定义聚合,逻辑类似于 "to become and stay true once it reached true":
create or replace function max_boolean(agg_state boolean)
returns boolean
immutable
strict
language plpgsql
as $$
begin
return agg_state;
end;
$$;
create or replace function max_boolean_aggregate(agg_state boolean, el boolean)
returns boolean
immutable
language plpgsql
as $$
begin
if (agg_state = true) then
return true;
else
if (el is null) then
return false;
else
return el;
end if;
else
return el;
end if;
end;
$$;
create aggregate max_boolean_aggregate (boolean)
(
sfunc = max_boolean_aggregate,
stype = boolean,
finalfunc = max_boolean
);
然后您的查询可以重写如下:
SELECT DISTINCT pename,coname, max_boolean_aggregate(presdoc = 2) AS present
FROM pe
left JOIN co ON coid=peco
left JOIN pres ON prespe=peid
WHERE peco = 1
group by pename, coname
它会显示您的人是否收到了文件。
甚至更多,它将能够支持多项检查:-)
只需将 max_boolean_aggregate() 中的条件更改为 (2,3) 中的 presdoc 即可。
基本上@Ilya Dyoshin 有解决方案。我只是把他的小评论放到一个答案中。首先找到现有的,然后 UNION 不存在的。使用 NOT IN 比 NOT EXIST 恕我直言更简单。
SELECT pename,coname,presdoc
FROM pe
LEFT JOIN co ON coid=peco
LEFT JOIN pres ON prespe=peid
WHERE peco = 1 AND presdoc=2
UNION
SELECT pename,coname,NULL AS present FROM pe
LEFT JOIN co ON coid=peco
WHERE peco=1 AND peid NOT IN(SELECT prespe FROM pres WHERE presdoc=2)
SQLFiddle: http://sqlfiddle.com/#!15/fb571/117
谢谢!
我正在尝试创建一个联系人报告,显示所有联系人和 select 在场的人。
存在存储在多对多table中。文档 ID 和出席者。
table如下:
CREATE TABLE pe
(peid int4, peco int4, pename varchar(30));
INSERT INTO pe
(peid, peco, pename)
VALUES
(1, 1,'Carl'),
(2, 1,'John'),
(3, 1,'Eric'),
(4, 2,'Donald')
;
CREATE TABLE co
(coid int, coname varchar(30));
INSERT INTO co
(coid, coname)
VALUES
(1,'Volvo'),
(2,'BMW'),
(3,'Microsoft'),
(4,'Apple')
;
There is a also a doc table that is not needed for this query
CREATE TABLE pres
(presid int4, presdoc int4, prespe int4);
INSERT INTO pres
(presid, presdoc, prespe)
VALUES
(1,1,1),
(2,2,2),
(3,2,3),
(4,3,1)
;
无效的查询(无论连接类型如何):
SELECT pename,coname,presdoc AS present
FROM pe
LEFT JOIN co ON coid=peco
LEFT JOIN pres ON prespe=peid
WHERE peco = 1 AND presdoc=2
这个查询的输出是
John Volvo present
Eric Volvo present
期望的输出是
Carl Volvo
John Volvo present
Eric Volvo present
SQLFiddle:
http://sqlfiddle.com/#!15/77b09/21
提前感谢您提供任何线索。
我认为问题出在条件 presdoc=2
上,它强制 return 只有存在的记录。这就是你需要的。
SELECT pename,
coname,
CASE
WHEN presdoc=2 THEN 'Present'
ELSE NULL
END AS Present
FROM pe
LEFT JOIN co ON coid=peco
LEFT JOIN pres ON prespe=peid
WHERE peco = 1
GROUP BY pename,
coname,
present
你能像这样执行吗(如果你只需要检查是否存在)
SELECT pename,coname,presdoc = 2 AS present
FROM pe
LEFT JOIN co ON coid=peco
LEFT JOIN pres ON prespe=peid
WHERE peco = 1
甚至更好
SELECT DISTINCT pename,coname,presdoc = 2 AS present
FROM pe
LEFT JOIN co ON coid=peco
LEFT JOIN pres ON prespe=peid
WHERE peco = 1
如果您只想检查您的文件是否已签发。然后另外你可以为你的布尔检查创建自定义聚合,逻辑类似于 "to become and stay true once it reached true":
create or replace function max_boolean(agg_state boolean)
returns boolean
immutable
strict
language plpgsql
as $$
begin
return agg_state;
end;
$$;
create or replace function max_boolean_aggregate(agg_state boolean, el boolean)
returns boolean
immutable
language plpgsql
as $$
begin
if (agg_state = true) then
return true;
else
if (el is null) then
return false;
else
return el;
end if;
else
return el;
end if;
end;
$$;
create aggregate max_boolean_aggregate (boolean)
(
sfunc = max_boolean_aggregate,
stype = boolean,
finalfunc = max_boolean
);
然后您的查询可以重写如下:
SELECT DISTINCT pename,coname, max_boolean_aggregate(presdoc = 2) AS present
FROM pe
left JOIN co ON coid=peco
left JOIN pres ON prespe=peid
WHERE peco = 1
group by pename, coname
它会显示您的人是否收到了文件。
甚至更多,它将能够支持多项检查:-)
只需将 max_boolean_aggregate() 中的条件更改为 (2,3) 中的 presdoc 即可。
基本上@Ilya Dyoshin 有解决方案。我只是把他的小评论放到一个答案中。首先找到现有的,然后 UNION 不存在的。使用 NOT IN 比 NOT EXIST 恕我直言更简单。
SELECT pename,coname,presdoc
FROM pe
LEFT JOIN co ON coid=peco
LEFT JOIN pres ON prespe=peid
WHERE peco = 1 AND presdoc=2
UNION
SELECT pename,coname,NULL AS present FROM pe
LEFT JOIN co ON coid=peco
WHERE peco=1 AND peid NOT IN(SELECT prespe FROM pres WHERE presdoc=2)
SQLFiddle: http://sqlfiddle.com/#!15/fb571/117
谢谢!