如何重用2个相同子查询检索的值?

问题描述 投票:2回答:1

我为我的问题准备了一个简单的SQL Fiddle

在PostgreSQL 10中,有2个表包含用户ID和用户社交网络数据(如给定的名称,照片):

CREATE TABLE words_users (
        uid     SERIAL PRIMARY KEY
);

CREATE TABLE words_social (
        sid     text     NOT NULL,
        social  integer  NOT NULL CHECK (0 < social AND social <= 64),
        given   text     NOT NULL CHECK (given ~ '\S'),
        uid     integer  NOT NULL REFERENCES words_users ON DELETE CASCADE,
        PRIMARY KEY(sid, social)
);

并且有2个表格可以存储游戏和聊天消息:

CREATE TABLE words_games (
        gid SERIAL PRIMARY KEY,
        player1 integer REFERENCES words_users(uid) ON DELETE CASCADE NOT NULL CHECK (player1 <> player2),
        player2 integer REFERENCES words_users(uid) ON DELETE CASCADE
);

CREATE TABLE words_chat (
        cid     BIGSERIAL PRIMARY KEY,
        created timestamptz NOT NULL,
        gid     integer NOT NULL REFERENCES words_games ON DELETE CASCADE,
        uid     integer NOT NULL REFERENCES words_users ON DELETE CASCADE,
        msg     text    NOT NULL
);

在这里,我用测试数据填充表格:

  • Facebook上的用户“Alice”,uid = 1,sid =“1111”(社交= 10)
  • 在Google上使用uid = 2和sid =“2222”的用户“Bob”(社交= 20)
  • 与gid = 100的游戏,两个用户都聊天

SQL:

INSERT INTO words_users (uid) VALUES (1), (2);

INSERT INTO words_games (gid, player1, player2) VALUES (100, 1, 2);

INSERT INTO words_social (sid, social, given, uid) VALUES 
('1111', 10, 'Alice', 1), 
('2222', 20, 'Bob', 2);

INSERT INTO words_chat (created, gid, uid, msg) VALUES 
(now() + interval '1 min', 100, 2, 'Hello, Alice'), 
(now() + interval '2 min', 100, 1, 'Hello, Bob'), 
(now() + interval '3 min', 100, 2, 'Nice to see you, Alice'), 
(now() + interval '4 min', 100, 1, 'Nice to see you too, Bob'), 
(now() + interval '5 min', 100, 2, 'Goodbye, Alice'), 
(now() + interval '6 min', 100, 1, 'Goodbye, Bob'); 

我正在尝试创建一个PHP脚本,当给出sid时,社交和gid将返回游戏gid的完整聊天。

我不仅仅使用gid参数来获取和显示聊天,因为我不希望其他用户监视他们没有玩的游戏。

另外我不能使用guid参数来识别用户调用我的脚本,我必须使用sid和社交参数(加上一个秘密,我从上面的测试用例中省略了)。

所以这是我的SQL语句来获取聊天:

SELECT uid, msg 
FROM words_chat 
WHERE gid=100 
AND EXISTS (select 1 from words_games where 
   (select uid from words_social 
   where sid='1111' and social=10) in (player1, player2)) 
ORDER BY CREATED ASC;

screenshot

它可以工作,但我还需要一件事,这使得它很复杂 - 对于每个聊天消息,我需要一个布尔值(而不是uid)来知道这是否是“Alice”的消息(这样我就可以绘制该行用粗体字)。

所以我试图这样做,SQL语句变得更加丑陋:

SELECT uid=(select uid from words_social 
   where sid='1111' and social=10) AS mine, msg 
FROM words_chat 
WHERE gid=100 
AND EXISTS (select 1 from words_games where 
   (select uid from words_social 
   where sid='1111' and social=10) in (player1, player2)) 
ORDER BY CREATED ASC;

screenshot 2

正如您在上面的截图中看到的那样,但是如何改进此查询呢?

SQL中是否有一种方法(即我不想在我的PHP脚本中保存uid值或使用pl / pgSQL)在第二个子查询中重用uid?

sql postgresql select subquery sql-subselect
1个回答
1
投票

使用joins更容易思考:

select wc.*, (wc.uid = ws.uid) as mine
from words_chat wc join
     words_games wg
     on wc.gid = wg.gid join
     words_social ws
     on ws.uid in (wg.player1, player2)
where wc.gid = 100 and
      ws.sid = '1111' and
      ws.social = 10
order by created asc;

Here是SQL小提琴。

© www.soinside.com 2019 - 2024. All rights reserved.