如何构造SQL查询中的字段IN子查询?

时间:2019-05-14 05:16:07

标签: c# sql postgresql

我正在使用在线提供的Yelp数据集。我已经尝试优化查询几天了。对于下面要列出的架构,我需要构造一个查询以提供以下内容:

  • 给出用户的UID,显示每个用户朋友的最新评论信息。

以下是架构:

CREATE TABLE business(
    bid varchar(40) PRIMARY KEY,
    name varchar(100),
    city varchar(40),
    state char(2),
    zip varchar(10),
    latitude real,
    longitude real,
    address varchar(100),
    numreviews INTEGER DEFAULT 0,
    numcheckins INTEGER DEFAULT 0,
    avgreview float DEFAULT 0,
    isopen bool,
    stars float
);

CREATE TABLE users(
    uid varchar(40) PRIMARY KEY,
    name varchar(40),
    avgstars float,
    fans INTEGER,
    coolvotes INTEGER,
    reviewcount INTEGER,
    funnyvotes INTEGER,
    signup varchar(20),
    usefulvotes INTEGER,
    latitude real,
    longitude real
);

CREATE TABLE reviews(
    rid varchar(40) PRIMARY KEY,
    bid varchar(40),
    uid varchar(40),
    stars float,
    date varchar(20),
    funny INTEGER,
    useful INTEGER, 
    cool INTEGER,
    text varchar(1024),
    FOREIGN KEY (uid) REFERENCES users(uid),
    FOREIGN KEY (bid) REFERENCES business(bid)
);

CREATE TABLE friends(
    uid varchar(40) REFERENCES users(uid),
    fid varchar(40) REFERENCES users(uid)
);

这是所需输出的一个示例: enter image description here

对于每个用户的朋友,我显示以下内容:

  • 朋友的名字
  • 最近一次评论中的商家名称
  • 最新评论中的商家所在城市
  • 他们最近的评论中的文字

当前,这是我成功的唯一“解决方案”。

步骤1:获取每个用户朋友的所有ID的列表。

SELECT fid from friends where uid = '{userId}'

这将返回每个用户朋友的所有用户ID的列表。所以我基本上有一个朋友ID列表。

第2步:有了这些信息,我在程序中对该列表运行了foreach循环。对于朋友ID列表的每次迭代,我执行以下查询并为循环的当前迭代提供临时朋友ID:

SELECT U.name, B.name, B.city, R.text, R.date FROM reviews as R, users as U, business as B
WHERE U.uid = '{currentFriendId}'
AND R.uid = '{currentFriendId}'
AND B.bid = R.bid
AND date = (SELECT MAX(date) FROM reviews WHERE uid = '{currentFriendId}')

每次运行此for循环时,我都会得到一行所需的输出,例如:

enter image description here

这很好...除了我必须为用户的每个朋友运行此查询。这是非常昂贵的。

目标:我正在尝试合并这两个查询,或者对其进行彻底修改,以在单个查询中一次生成所有行。

问题:鉴于提供的信息,我该如何解决我的查询以通过单个查询生成所有这些信息?

5 个答案:

答案 0 :(得分:1)

这似乎是每个组的前n个问题。

一种方法是使用横向连接。

确保在../Inc (should be by default) ../Drivers/CMSIS/Device/ST/STM32F4xx/Include (should be by default) ../Drivers/STM32F4xx_HAL_Driver/Inc (should be by default) ../Drivers/STM32F4xx_HAL_Driver/Inc/Legacy (should be by default) ../Drivers/CMSIS/Include (should be by default) "${workspace_loc:/${ProjName}/Drivers/Device/ST/STM32F4xx/Include}" "${workspace_loc:/${ProjName}/Drivers/CMSIS/Core/Include}" "${workspace_loc:/${ProjName}/Drivers/CMSIS/Core_A/Include}" "${workspace_loc:/${ProjName}/Drivers/CMSIS/DSP/Include}" 的{​​{1}}表上有索引。综合索引。一个索引按此顺序在两列上。

类似这样的东西:

reviews

查询

(uid, date)

答案 1 :(得分:0)

这应该很好。

SELECT name FROM employees as E
WHERE E.uid IN (SELECT uid FROM employees WHERE name = 'John')

您不需要像单个真值匹配查询那样进行相等的比较。

答案 2 :(得分:0)

跟着Manos的回答,我不确定我为什么要限制每个fid的原因

SELECT U.name, B.name, B.city, R.text, R.date 
    FROM business AS B 
    INNER JOIN reviews AS R ON B.bid = R.bid 
    INNER JOIN users AS U ON R.uid = U.uid 
    WHERE (R.date = (SELECT MAX(X.date) FROM reviews AS X WHERE X.uid = R.uid)) 
    AND (R.uid IN (SELECT fid FROM friends));

如果您的问题是查询仅在一行中显示,则应删除该 where uid = 以获取所有uid的结果。

答案 3 :(得分:0)

我也和Vladimir Baranov大致在同一时间得到了答案,但是我也会发布我的版本。我不保证它很漂亮:

SELECT R.name as user_name, B.name as business_name, B.City, R.text
FROM (SELECT bid, name, text 
     FROM (SELECT R.rid, R.bid, R.uid, R.text, max_date
        FROM reviews as R INNER JOIN 
           (SELECT uid, MAX(date) as max_date FROM reviews WHERE uid IN (SELECT fid from friends where uid = 'BfcNxKpnF9z5wJLXY7elRg') GROUP BY uid) sub
            ON R.uid = sub.uid AND R.date = sub.max_date) as review_info
     INNER JOIN users
     on review_info.uid = users.uid) as R
INNER JOIN business as B
ON R.bid = B.bid

答案 4 :(得分:-1)

检查您发布的架构后,我使用MySQL创建数据库并使用以下示例数据填充表:

INSERT INTO users (uid, name) VALUES
('user1', 'user1 name'),
('user2', 'user2 name'),
('user3', 'user3 name'),
('user4', 'user4 name'),
('user5', 'user5 name');

INSERT INTO friends (uid, fid) VALUES
('user1', 'user2'), ('user1', 'user3'),
('user2', 'user4'), ('user2', 'user5');

INSERT INTO business (bid, name, city) VALUES
('b1', 'business 1', 'city 1'),
('b2', 'business 2', 'city 2'),
('b3', 'business 3', 'city 3'),
('b4', 'business 4', 'city 4');

INSERT INTO reviews (rid, bid, uid, stars, date, text) VALUES
('r1', 'b1', 'user1', 5, '2019-05-01', 'blah'),
('r2', 'b2', 'user1', 5, '2019-05-02', 'blah'),
('r3', 'b3', 'user1', 5, '2019-05-03', 'blah'),
('r4', 'b1', 'user2', 4, '2019-05-11', 'blah'),
('r5', 'b2', 'user3', 3, '2019-05-12', 'blah'),
('r6', 'b1', 'user4', 5, '2019-05-13', 'blah');

这使我可以通过在MySQL Workbench中执行查询来验证我提出的原始解决方案是否正确。 我假设您提到的“失败完成”与查询本身无关,而是您使用的数据库连接api的暂时失败。 请注意,该代码已更新,以纳入Mihail Shishkov提出的使用参数的建议。

-- Display review information originating from friends of user1
-- DECLARE @UID varchar(40);    -- Uncomment for MS-SQL (variables need to be declared)
SET @UID = 'user1';

SELECT U.name, B.name, B.city, R.text, R.date 
FROM business AS B
INNER JOIN reviews AS R ON B.bid = R.bid
INNER JOIN users AS U ON R.uid = U.uid
WHERE (R.date = (SELECT MAX(X.date) FROM reviews AS X WHERE (X.uid = R.uid)))
  AND (R.uid IN (SELECT F.fid FROM friends AS F WHERE (F.uid = @UID)));

基于示例数据,并使用' user1 '作为@UID参数的值,查询结果为:

name        name        city    text  date
------------------------------------------------
user2 name  business 1  city 1  blah  2019-05-11
user3 name  business 2  city 2  blah  2019-05-12

此外,我假设在您的架构上下文中(如在现实世界中)友谊是一种双向关系,这意味着“ user1”和“ user2”之间的友谊仅需通过带有值('user1','user2')和 reverse ('user2','user1')的表'friends'是不必要的。 因此,出于完整性考虑,您可以使用以下查询:

-- Display review information originating from friends of user2
SET @UID = 'user2';

SELECT U.name, B.name, B.city, R.text, R.date 
FROM business AS B
INNER JOIN reviews AS R ON B.bid = R.bid
INNER JOIN users AS U ON R.uid = U.uid
WHERE (R.date = (SELECT MAX(X.date) FROM reviews AS X WHERE (X.uid = R.uid)))
  AND (R.uid IN (SELECT F.fid FROM friends AS F WHERE (F.uid = @UID) UNION
                 SELECT F.uid FROM friends AS F WHERE (F.fid = @UID)));

现在,使用' user2 '作为@UID参数的值和查询的扩展版本,我们获得以下结果:

name        name        city    text  date
------------------------------------------------
user1 name  business 3  city 3  blah  2019-05-03
user4 name  business 1  city 1  blah  2019-05-13

如果您认为答案是可以接受的,我将不胜感激。