Sql 哪里IN条件和子查询中的多个列

Sql 哪里IN条件和子查询中的多个列,sql,postgresql,join,subquery,postgresql-9.5,Sql,Postgresql,Join,Subquery,Postgresql 9.5,是否可以重写SQL查询 SELECT DISTINCT ON (uid) uid, female, given, photo, place FROM words_social WHERE uid IN (SELECT player1 FROM games) OR uid IN (SELECT player2 FROM games) ORDER BY uid, stamp DESC 其中在子查询中获取

是否可以重写SQL查询

SELECT DISTINCT ON (uid)
        uid,
        female,
        given,
        photo,
        place
FROM words_social
WHERE uid IN (SELECT player1 FROM games)
        OR uid IN (SELECT player2 FROM games)
ORDER BY uid, stamp DESC
其中在子查询中获取第一列
player1
,然后从同一个表中获取列
player2

我四处搜索过,似乎应该在这里使用连接,而不是2个子查询,但不知道具体如何使用

只是为了提供更多的上下文-下面是有问题的两个表

CREATE TABLE words_social (
        sid varchar(255) NOT NULL,

        social integer NOT NULL CHECK (0 <= social AND social <= 6),
        female integer NOT NULL CHECK (female = 0 OR female = 1),
        given  varchar(255) NOT NULL CHECK (given ~ '\S'),
        family varchar(255),
        photo  varchar(255) CHECK (photo ~* '^https?://...'),
        place  varchar(255),
        stamp  integer NOT NULL,            /* Only the most recent stamp is used */

        uid integer NOT NULL REFERENCES words_users ON DELETE CASCADE,
        PRIMARY KEY(sid, social)
);

CREATE TABLE words_games (
        gid SERIAL PRIMARY KEY,

        created timestamptz NOT NULL,
        finished timestamptz,

        player1 integer REFERENCES words_users(uid) ON DELETE CASCADE NOT NULL,
        player2 integer REFERENCES words_users(uid) ON DELETE CASCADE,

        played1 timestamptz,
        played2 timestamptz,

        mid integer /* REFERENCES words_moves */,

        score1 integer NOT NULL CHECK (score1 >= 0),
        score2 integer NOT NULL CHECK (score2 >= 0),

        hand1 varchar[7] NOT NULL,
        hand2 varchar[7] NOT NULL,
        pile  varchar[116] NOT NULL,

        letters varchar[15][15] NOT NULL,
        values integer[15][15] NOT NULL,
        bid integer NOT NULL REFERENCES words_boards ON DELETE CASCADE
);

当中的
不够时,使用
存在

SELECT DISTINCT ON (uid)
        uid,
        female,
        given,
        photo,
        place
FROM words_social ws
WHERE EXISTS
(
  SELECT *
  FROM games g
  WHERE ws.uid IN (g.player1, g.player2)
)
ORDER BY uid, stamp DESC

中的
不够时,使用
存在

SELECT DISTINCT ON (uid)
        uid,
        female,
        given,
        photo,
        place
FROM words_social ws
WHERE EXISTS
(
  SELECT *
  FROM games g
  WHERE ws.uid IN (g.player1, g.player2)
)
ORDER BY uid, stamp DESC

为了证明您不需要CTE,这里是您在没有CTE的情况下重写的查询

  • 我不得不猜测一些表格结构,因为问题不完整
  • 一个预先准备好的语句而不是一个函数(子同步器是类似的)
  • 重写播放器1第2页副本;这可以通过大小写表达式等轻松处理
  • 使用
    not exists
    (也可以通过
    行号()重写最近的社交记录(按uid顺序按tstamp DESC划分)rn…其中rn=1
  • 删除了一些装饰字段


为了证明您不需要CTE,这里是您在没有CTE的情况下重写的查询

  • 我不得不猜测一些表格结构,因为问题不完整
  • 一个预先准备好的语句而不是一个函数(子同步器是类似的)
  • 重写player1player2副本;这可以通过大小写表达式等轻松处理
  • 使用
    not exists
    (也可以通过
    行号()重写最近的社交记录(按uid顺序按tstamp DESC划分)rn…其中rn=1
  • 删除了一些装饰字段


我认为这是一个相当糟糕的建议。当你想从
单词\u social
中选择在
游戏中找到匹配项时,那么在游戏中找到匹配项仅仅是一个标准,最好是在where子句中。为什么你要建议这种过时的连接语法,这种语法在1992年变得多余?你不应该这样做。我认为这是相当糟糕的建议。当你想从
Word_social
中选择在
游戏中找到匹配项的位置时,那么在游戏中找到匹配项仅仅是一个标准,最好在where子句中找到。为什么你要建议这种过时的连接语法,这种语法在1992年变得多余?你不应该这样做。注意:表Word_moves没有DDL。顺便说一句:优化的最佳方法是避免CTE(至少最初是这样)CTE是优化障碍。此外,“社交”一词的含义我也不清楚。什么是
sid
为什么是varchar(255)以及主键的起始部分?为什么
stamp
不是PK的一部分?它似乎是时间戳或某种版本号。在
words\u social
中,我保存用户信息(姓名、姓氏、居住地、性别)从Facebook、Twitter和其他社交网络获取。列
stamp
指示哪些用户记录是最新的(应该用于显示我的html5游戏中的玩家信息)。表
words\u moves
在这里不重要……它只保留玩家移动的日志(play、demit、swap)在游戏中。还有更多的表格-
words\u boards
和20多个…它们对我的问题不重要。我不寻求PKs方面的建议,它们工作得很好…从下至上构建查询的强烈建议:从games+user1+user2开始。然后,可能(左)加入来自社交cruft的其他(可选)数据。然后(可能)通过添加引用表中的其他列来装饰查询。在需要之前避免CTE。我不能在这里避免CTE,因为我只需要
words\u social
表中带有最新
戳记的用户记录。需要CTE完全是胡说八道;请参阅我的答案。注意:表words\u移动没有DDL.BTW:优化的最佳方法是避免CTE(至少在最初)CTE是优化障碍。此外,我不清楚“社交”一词的含义。什么是
sid
为什么是varchar(255)以及主键的起始部分?为什么
stamp
不是PK的一部分?它似乎是时间戳或某种版本号。在
words\u social
中,我保存用户信息(姓名、姓氏、居住地、性别)从Facebook、Twitter和其他社交网络获取。列
stamp
指示哪些用户记录是最新的(应该用于显示我的html5游戏中的玩家信息)。表
words\u moves
在这里不重要……它只保留玩家移动的日志(play、demit、swap)在游戏中。还有更多的表格-
words\u boards
和20多个…它们对我的问题不重要。我不寻求PKs方面的建议,它们工作得很好…从下至上构建查询的强烈建议:从games+user1+user2开始。然后,可能(左)加入来自社交cruft的其他(可选)数据。然后(可能)通过添加引用表中的其他列来装饰查询。在需要之前避免CTE。我不能在这里避免CTE,因为我只需要
words\u social
表中带有最新
戳记的用户记录。需要CTE完全是胡说八道;请参阅我的答案。谢谢!所以您使用
不存在(选择…
subquery可在
words\u social
表中查找每个
uid
?的最新记录。这只是获取最大/最新记录的方法之一。其他方法是通过窗口聚合子查询或行号()。谢谢!因此您使用
不存在(选择…)
subquery在
words\u social
表中查找每个
uid
的最新记录。这只是获取最大/最新记录的方法之一。其他方法是聚合子查询或
SELECT DISTINCT ON (uid)
        uid,
        female,
        given,
        photo,
        place
FROM words_social ws
WHERE EXISTS
(
  SELECT *
  FROM games g
  WHERE ws.uid IN (g.player1, g.player2)
)
ORDER BY uid, stamp DESC
PREPARE rewrite2(integer) AS
        SELECT g.gid
            , EXTRACT(EPOCH FROM g.created)::int AS created
            , EXTRACT(EPOCH FROM g.finished)::int AS finished
            , g.player1
            , g.player2 -- can be NULL
            , EXTRACT(EPOCH FROM g.played1)::int AS played1
            , EXTRACT(EPOCH FROM g.played2)::int AS played2
            , g.score1
            , g.score2
            , ARRAY_TO_STRING(g.hand1, '') AS hand1
            , REGEXP_REPLACE(ARRAY_TO_STRING(g.hand2, ''), '.', '?', 'g') AS hand2
            , g.letters
            , g.values
            , g.bid
            , m.tiles AS last_tiles
            , m.score AS last_score
            , s1.female AS female1
            , s1.given AS given1
            , s2.female AS female2
            , s2.given AS given2
    FROM words_games g
    LEFT JOIN words_moves m USING(mid)
    LEFT JOIN words_social s1 ON s1.uid = g.player1
        AND NOT EXISTS( SELECT *
            FROM words_social nx WHERE s1.uid = nx.uid
            AND nx.stamp > s1.stamp)
    LEFT JOIN words_social s2 ON s2.uid = g.player2
        AND NOT EXISTS( SELECT *
            FROM words_social nx WHERE s2.uid = nx.uid
            AND nx.stamp > s2.stamp)
    WHERE (g.player1 = $1 OR g.player2 = $1)
    AND (g.finished IS NULL OR g.finished > CURRENT_TIMESTAMP - INTERVAL '1 day')
        ;

EXPLAIN EXECUTE rewrite2(1);