SQL:我可以在窗口函数中引用/访问数据当前行吗?

时间:2017-10-11 17:37:58

标签: mysql sql postgresql

这是一个例子。假设我有下表:

 id     | list
--------+----------
 10     |
        | 10,20
 20     | 10,20

对于每个id值,我想计算具有list值的行数,其中包含id值。结果将是这样的:

 id     | count of lists
--------+----------
 10     | 2
        | 0
 20     | 2

我建议应该使用一个窗口函数,但似乎我无法从这样的函数中访问id值。

我完全同意 BAD 设计。这个问题是关于可能性的。

任何MySQL / PostgreSQL解决方案都没问题。

2 个答案:

答案 0 :(得分:0)

假设您正在使用MySQL,并假设您的表名为test,并假设两列都是字符串类型:

SELECT
  t1.id, count(t2.list)
FROM
(test t1 LEFT JOIN test t2 ON
  (t2.list LIKE CONCAT('%,', t1.id, ',%')) OR
  (t2.list LIKE CONCAT('%,', t1.id)) OR
  (t2.list LIKE CONCAT(t1.id, ',%')))
GROUP BY t1.id;

请注意,此解决方案可能会非常慢,具体取决于您拥有的记录数量以及list字段中字符串的平均长度。

如果你需要更快的东西,我认为它不可能只是一个查询。也许我们必须为此编写存储过程或某些应用程序逻辑,或者使用其他表或列以及一系列多个SQL语句。

答案 1 :(得分:0)

在开始之前,如上所述,这是一个糟糕的设计。但是,我会这样查询它:

CREATE TABLE #Lists (id int, list varchar(500));
INSERT INTO #Lists (id, list) VALUES
    (10, NULL), (NULL, '10,20'), (20, '10,20');

WITH cte AS (
    SELECT LEFT(list, INSTR(list, '%,%')-1) AS value, SUBSTRING(list, INSTR(list, '%,%') + 1, 500) AS list FROM #Lists
    UNION ALL
    SELECT CASE WHEN list LIKE ('%,%') THEN LEFT(list, INSTR(list, '%,%')-1) ELSE list END AS value, CASE WHEN list LIKE ('%,%') THEN SUBSTRING(list, INSTR(list, '%,%') + 1, 500) END AS list FROM cte 
    WHERE CHAR_LENGTH(list) > 0
)

SELECT value, COUNT(*) FROM cte GROUP BY value;

DROP TABLE #Lists;

此解决方案允许list字符串中的任意数量的值(如'10,20,30')。

理想情况下,列表值应存储在单独的表中,以便每条记录都有一个值,例如CREATE TABLE BetterDesign (id int, value int) INSERT INTO BetterDesign (id, value) VALUES (10, NULL), (NULL, 10), (NULL, 20), (20, 10), (20, 20)。除了其他一百万个原因外,查询SELECT value, COUNT(*) FROM BetterDesign GROUP BY value会更好。话虽如此,我理解遗留系统的痛苦。