这是我需要的结果,简化:
select name, phonenumber
from contacttmp
left outer join phonetmp on (contacttmp.id = phonetmp.contact_id);
name | phonenumber
-------+--------------
bob | 111-222-3333
bob | 111-222-4444
bob | 111-222-5555
frank | 111-222-6666
joe | 111-222-7777
但查询显示名称,我试图在第一个结果后省略名称:
name | phonenumber
-------+--------------
bob | 111-222-3333
| 111-222-4444
| 111-222-5555
frank | 111-222-6666
joe | 111-222-7777
以下是我制作示例表和数据的方法:
create table contacttmp (id serial, name text);
create table phonetmp (phoneNumber text, contact_id integer);
select * from contacttmp;
id | name
----+-------
1 | bob
2 | frank
3 | joe
select * from phonetmp ;
phonenumber | contact_id
--------------+------------
111-222-3333 | 1
111-222-4444 | 1
111-222-5555 | 1
111-222-6666 | 2
111-222-7777 | 3
我正在使用PHP中的联系人程序,并且要求显示结果,但如果同一记录有多个结果,则在显示第一条记录后省略其他字段。
从postgres tutorial join示例中,我正在使用左外连接执行此类操作:
SELECT *
FROM weather LEFT OUTER JOIN cities ON (weather.city = cities.name);
city | temp_lo | temp_hi | prcp | date | name | location
--------------+---------+---------+------+------------+---------------+-----------
Hayward | 37 | 54 | | 1994-11-29 | |
San Francisco | 46 | 50 | 0.25 | 1994-11-27 | San Francisco | (-194,53)
San Francisco | 43 | 57 | 0 | 1994-11-29 | San Francisco | (-194,53)
我无法弄清楚如何或者是否有可能改变上述查询,以便在第一个结果之后不显示其他字段。
例如,如果我们添加子句“WHERE location ='( - 194,53)'”我们不希望第二个(和第三个,如果有的话)结果显示除location之外的列,所以查询(加上额外的东西),结果如下:
SELECT *
FROM weather LEFT OUTER JOIN cities ON (weather.city = cities.name)
WHERE location = '(-194,53)';
city | temp_lo | temp_hi | prcp | date | name | location
--------------+---------+---------+------+------------+---------------+-----------
San Francisco | 46 | 50 | 0.25 | 1994-11-27 | San Francisco | (-194,53)
| | | | | | (-194,53)
是否可以使用某种JOIN或排除或其他查询?或者在获得所有结果后我是否必须在PHP中删除这些字段(宁愿不这样做)。
为避免混淆,我需要获得如下结果集:
city | temp_lo | temp_hi | prcp | date | name | location
--------------+---------+---------+------+------------+---------------+-----------
San Francisco | 46 | 50 | 0.25 | 1994-11-27 | San Francisco | (-194,53)
| | | | | | (-19,5)
| | | | | | (-94,3)
Philadelphia | 55 | 60 | 0.1 | 1995-12-12 | Philadelphia | (-1,1)
| | | | | | (-77,55)
| | | | | | (-3,33)
如果具有不同位置的同一记录(城市)的任何其他结果只显示不同的位置。
答案 0 :(得分:3)
您可以在SQL中执行此类逻辑,但不建议这样做。 SQL查询的结果集采用表格格式。表格表示无序集合,通常所有列都具有相同的含义。
因此,拥有一个依赖于“前一行”值的结果集不是使用SQL的正确方法。虽然你可以在Postgres中得到这个结果,但我不推荐它。通常,这种格式化在应用程序端完成。
答案 1 :(得分:2)
如果您想避免重复相同的信息,可以使用一个窗口函数来告诉您该行中该行的位置(PARTITION
用于此目的,而不是{{1}中的一个组感觉),然后隐藏您不想重复的列的文本,如果该组中的位置大于1。
GROUP BY
这应该给你这个:
WITH joined_results AS (
SELECT
w.city, c.location, w.temp_lo, w.temp_hi, w.prcp, w.date,
ROW_NUMBER() OVER (PARTITION BY w.city, c.location ORDER BY date) AS pos
FROM weather w
LEFT OUTER JOIN cities c ON (w.city = c.name)
ORDER BY w.city, c.location
)
SELECT
CASE WHEN pos > 1 THEN '' ELSE city END,
CASE WHEN pos > 1 THEN '' ELSE location END,
temp_lo, temp_hi, prcp, date
FROM joined_results;
要了解 city | location | temp_lo | temp_hi | prcp | date
---------------+-----------+---------+---------+------+------------
Hayward | | 37 | 54 | | 1994-11-29
San Francisco | (-194,53) | 46 | 50 | 0.25 | 1994-11-27
| | 43 | 57 | 0 | 1994-11-29
的作用,可能值得查看ROW_NUMBER() OVER (PARTITION BY w.city, c.location ORDER BY date) AS pos
的内容:
SELECT * FROM joined_results
之后,只需使用 city | location | temp_lo | temp_hi | prcp | date | pos
---------------+-----------+---------+---------+------+------------+-----
Hayward | | 37 | 54 | | 1994-11-29 | 1
San Francisco | (-194,53) | 46 | 50 | 0.25 | 1994-11-27 | 1
San Francisco | (-194,53) | 43 | 57 | 0 | 1994-11-29 | 2
替换您不想要的空格。
(这就是说,我通常更喜欢在表示层而不是在查询中。)
答案 2 :(得分:1)
考虑下面小提琴中略有修改的测试用例。
对于处理每列单列的简单情况,与上一个行和窗口函数lag()
进行比较可以完成工作:
SELECT CASE WHEN lag(c.contact) OVER (ORDER BY c.contact, p.phone_nr)
= c.contact THEN NULL ELSE c.contact END
, p.phone_nr
FROM contact c
LEFT JOIN phone p USING (contact_id);
您可以为 n列重复此操作,但这很乏味
SELECT c.*, p.phone_nr
FROM (
SELECT *
, row_number() OVER (PARTITION BY contact_id ORDER BY phone_nr) AS rn
FROM phone
) p
LEFT JOIN contact c ON c.contact_id = p.contact_id AND p.rn = 1;
类似于"反向LEFT JOIN"。这是假设引用完整性(contact
中没有丢失的行。此外,phone
中没有任何条目的联系人不在结果中。如果需要,可以轻松添加。
除此之外,您在第一个示例中的查询显示出一个新手错误。
SELECT * FROM weather LEFT OUTER JOIN cities ON (weather.city = cities.name)
WHERE location = '(-194,53)';
在右表中没有LEFT JOIN
和WHERE
子句的组合。没有意义。详细说明:
除了测试存在...