如何删除笛卡尔连接
How to remove the Cartesian Join
我有两个 table,其结构类似于以下 2 table。
姓名:
ID | FirstName | LastName
__________________________
123 Akshay kumar
123 Salman khan
123 Johnny lever
123 Tom Cruise
城市:
ID | City
___________
123 Pune
现在当我运行下面的查询时:
Select N.*,C.* from Name N,City C where C.ID=N.ID and N.ID=123;
ID | FirstName | LastName | ID | City
_____________________________________________
123 Akshay kumar 123 Pune
123 Salman khan 123 Pune
123 Johnny lever 123 Pune
123 Tom Cruise 123 Pune
Pune 重复了 4 次。而我想要如下输出:
ID | FirstName | LastName | ID | City
_____________________________________________
123 Akshay kumar 123 Pune
123 Salman khan
123 Johnny lever
123 Tom Cruise
姓名和城市 Table 数据之间没有关系,除了 ID Coumn。
此外,对于相同的 ID,名称 table 的条目数不一定要多于城市 Table 的条目数。
对于相同的 ID,城市 Table 也可以比名称 Table 拥有更多的行。(所以 Left Join 将不起作用)
请大家帮忙。
这是通常会在您的表示层中处理的要求,例如PHP,或任何正在使用您的数据库的工具。也就是说,我们实际上可以使用 ROW_NUMBER
:
来处理您的要求
WITH cte AS (
SELECT n.FirstName, n.LastName, c.ID, c.City,
ROW_NUMBER() OVER (PARTITION BY c.ID, c.City ORDER BY n.LastName, n.FirstName) rn
FROM Name n
INNER JOIN City c ON c.ID = n.ID
WHERE n.ID = 123
)
SELECT ID, FirstName, LastName,
CASE WHEN rn = 1 THEN ID END AS ID,
CASE WHEN rn = 1 THEN City END AS City
FROM cte
ORDER BY
ID,
LastName,
FirstName;
您不是要删除笛卡尔积。
您实际上是想在报告中添加 "break"。对于 Oracle,请执行以下操作:
break on city
MySql,你运气不好。如果没有一些重要的编码,它就没有这样的结构。看到这个答案:.
对于其他报告工具,技术会有所不同,但请理解,您实际上是在问报告问题,而不是 SQL 问题,并且您正在寻找的报告结构是 "break" 有时称为 "control break".
您可以使用row_number
解析函数如下:
select n.id, n.firstname, n.lastname, c.id, c.city,
(select t.*, row_number() over (partition by id order by t.firstname) as rn from name t) n
left join
(select t.*, row_number() over (partition by id order by t.city) as rn from city t) c
on n.id = c.id and n.rn = c.rn
order by n.id, n.rn
我有两个 table,其结构类似于以下 2 table。 姓名:
ID | FirstName | LastName
__________________________
123 Akshay kumar
123 Salman khan
123 Johnny lever
123 Tom Cruise
城市:
ID | City
___________
123 Pune
现在当我运行下面的查询时:
Select N.*,C.* from Name N,City C where C.ID=N.ID and N.ID=123;
ID | FirstName | LastName | ID | City
_____________________________________________
123 Akshay kumar 123 Pune
123 Salman khan 123 Pune
123 Johnny lever 123 Pune
123 Tom Cruise 123 Pune
Pune 重复了 4 次。而我想要如下输出:
ID | FirstName | LastName | ID | City
_____________________________________________
123 Akshay kumar 123 Pune
123 Salman khan
123 Johnny lever
123 Tom Cruise
姓名和城市 Table 数据之间没有关系,除了 ID Coumn。 此外,对于相同的 ID,名称 table 的条目数不一定要多于城市 Table 的条目数。 对于相同的 ID,城市 Table 也可以比名称 Table 拥有更多的行。(所以 Left Join 将不起作用) 请大家帮忙。
这是通常会在您的表示层中处理的要求,例如PHP,或任何正在使用您的数据库的工具。也就是说,我们实际上可以使用 ROW_NUMBER
:
WITH cte AS (
SELECT n.FirstName, n.LastName, c.ID, c.City,
ROW_NUMBER() OVER (PARTITION BY c.ID, c.City ORDER BY n.LastName, n.FirstName) rn
FROM Name n
INNER JOIN City c ON c.ID = n.ID
WHERE n.ID = 123
)
SELECT ID, FirstName, LastName,
CASE WHEN rn = 1 THEN ID END AS ID,
CASE WHEN rn = 1 THEN City END AS City
FROM cte
ORDER BY
ID,
LastName,
FirstName;
您不是要删除笛卡尔积。
您实际上是想在报告中添加 "break"。对于 Oracle,请执行以下操作:
break on city
MySql,你运气不好。如果没有一些重要的编码,它就没有这样的结构。看到这个答案:
对于其他报告工具,技术会有所不同,但请理解,您实际上是在问报告问题,而不是 SQL 问题,并且您正在寻找的报告结构是 "break" 有时称为 "control break".
您可以使用row_number
解析函数如下:
select n.id, n.firstname, n.lastname, c.id, c.city,
(select t.*, row_number() over (partition by id order by t.firstname) as rn from name t) n
left join
(select t.*, row_number() over (partition by id order by t.city) as rn from city t) c
on n.id = c.id and n.rn = c.rn
order by n.id, n.rn