【问题标题】:Alias scoping in SQLSQL 中的别名范围
【发布时间】:2015-02-12 18:41:08
【问题描述】:

我在 SQLite3 数据库上遇到一个复杂查询的问题,我认为这与我对如何引用 select 语句返回的结果表中的列存在误解有关,尤其是在涉及别名时.

这是一个示例表 - 电影 ID 列表,其中每个演员在电影中工作的一行:

CREATE TABLE movie_actor (imdb_id TEXT, actor TEXT);
INSERT INTO movie_actor VALUES('44r4', 'John Doe');
INSERT INTO movie_actor VALUES('44r4', 'Jane Doe');
INSERT INTO movie_actor VALUES('44r4', 'Jermaine Doe');
INSERT INTO movie_actor VALUES('44r4', 'Jacob Doe');
INSERT INTO movie_actor VALUES('55r5', 'John Doe');
INSERT INTO movie_actor VALUES('55r5', 'Jane Doe');
INSERT INTO movie_actor VALUES('55r5', 'Nathan Deer');
INSERT INTO movie_actor VALUES('66r6', 'Bob Duck');
INSERT INTO movie_actor VALUES('66r6', 'John Doe');
INSERT INTO movie_actor VALUES('66r6', 'Jermaine Doe');
INSERT INTO movie_actor VALUES('66r6', 'Jane Doe');
INSERT INTO movie_actor VALUES('77r7', 'John Doe');

我试图找出每对演员在所有电影中相互合作的次数。我决定通过自我加入来解决这个问题,但遇到了问题,我会得到诸如“John Doe,Jane Doe,3”和“Jane Doe,John Doe,3”之类的记录对 - 这真的是一回事,我只想计算第一个版本。这是产生的代码:

SELECT DISTINCT 
    CASE WHEN d.actor_1 > d.actor_2 THEN d.actor_1 ELSE d.actor_2 END d.actor_1, 
    CASE WHEN d.actor_2 > d.actor_1 THEN d.actor_2 ELSE d.actor_1 END d.actor_2, 
    d.v 
FROM ( 
    SELECT c.actor_1 AS actor_1, c.actor_2 AS actor_2, COUNT(*) AS v 
    FROM ( 
        SELECT a.actor AS actor_1, b.actor AS actor_2 
        FROM movie_actor a JOIN movie_actor b ON a.imdb_id=b.imdb_id 
        ) AS c 
    WHERE c.actor_1 <> c.actor_2 
    GROUP BY c.actor_1, c.actor_2 
    HAVING COUNT(*) > 2 
    ORDER BY COUNT(*) DESC 
    LIMIT 20 
    ) 
    AS d

这不运行,但我不知道为什么。我的假设是我没有正确使用别名,但我真的不知道。有什么想法吗?

(SQL Fiddle link here)

【问题讨论】:

    标签: sql sqlite


    【解决方案1】:

    如果我们添加条件a.actor &lt; b.actor,我们会得到一个更简单的查询。这排除了具有相同参与者的配对,同时它消除了交换参与者的需要。

    SELECT
        a.actor AS actor_1, b.actor AS actor_2, COUNT(*) AS v
    FROM
        movie_actor a
        INNER JOIN movie_actor b
            ON a.imdb_id = b.imdb_id
    WHERE
        a.actor < b.actor
    GROUP BY a.actor, b.actor
    ORDER BY COUNT(*) DESC, a.actor, b.actor 
    LIMIT 20 
    

    注意:SQL 在连接时总是创建一个叉积,即它创建所有可能的与连接条件匹配的记录组合。因此对于 imdb 55r5(包括 3 个演员),它将首先生成以下 3 x 3 = 9 对:

    John Doe      John Doe
    John Doe      Jane Doe
    John Doe      Nathan Deer
    Jane Doe      John Doe
    Jane Doe      Jane Doe
    Jane Doe      Nathan Deer
    Nathan Deer   John Doe
    Nathan Deer   Jane Doe
    Nathan Deer   Nathan Deer
    

    然后 WHERE 子句排除所有 a >= b 对,我们得到

    John Doe      Nathan Deer
    Jane Doe      John Doe
    Jane Doe      Nathan Deer
    

    【讨论】:

    • 根据 OP 的数据,您的查询不会返回您所说的内容。 (只返回一行。)
    • have子句条件应该是&gt;=2
    • 字符串比较在词法顺序上起作用:'xyz' &gt; 'abc'
    • CASE ... END 之后是d.actor_1。新别名应改为 AS actor_1
    • 您的交换逻辑错误。我想应该是CASE WHEN d.actor_1 &gt; d.actor_2 THEN d.actor_1 ELSE d.actor_2 END AS actor_1, CASE WHEN d.actor_1 &gt; d.actor_2 THEN d.actor_2 ELSE d.actor_1 END AS actor_2。您反转了条件以及输出字段,因此第二个 CASE 给出了与第一个相同的结果。反转条件或字段,但不能同时反转!
    【解决方案2】:

    首先生成不同的对,然后计算它们。

    select actor_1, actor_2, count(*)
    from (select distinct a.imdb_id, a.actor as actor_1, b.actor as actor_2
          from movie_actor a
          inner join movie_actor b on a.imdb_id = b.imdb_id
          where a.actor < b.actor) x
    group by actor_1, actor_2
    order by actor_1, actor_2;
    
    actor_1 actor_2 计数(*) ---------- ---------- ---------- Bob Duck Jane Doe 1 鲍勃鸭杰梅因 D 1 鲍勃鸭约翰·多伊 1 雅各布·多伊·简·多伊 1 雅各布·多伊·杰梅因 D 1 雅各布·多伊·约翰·多伊 1 简·多伊·杰梅因 D 2 简·多伊·约翰·多伊 3 简·多伊·内森·迪 1 杰梅因 D 约翰·多伊 2 约翰·多·内森·迪 1

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多