SQL - 从两个不同的表返回数据

Posted

技术标签:

【中文标题】SQL - 从两个不同的表返回数据【英文标题】:SQL - Return data from two differnt tables 【发布时间】:2016-11-12 18:11:34 【问题描述】:

我有两个表 BOOKINGS 和 WORKERS。基本上有一个工人的桌子,还有一个桌子来跟踪工人在一个时间框架内必须做什么(预订)。例如,Jeff 属于 WORKERS 表,在 BOOKING 表中,Jeff 从 2016 年 11 月 10 日到 2016 年 11 月 15 日工作。

我正在尝试检查是否有可用的工作人员。假设我需要从 2016 年 11 月 11 日到 2016 年 11 月 14 日完成一些事情。我需要能够查看当时是否有未预订的工人,并显示所有可用于该工作的工人。 因此,我查询预订以检查请求的时间在开始结束日期之间是否有可用的工作人员。

但是,我这样做的方式是连接表 WORKERS 和 BOOKINGS,它只返回 BOOKINGS 之外的匹配和不匹配数据。例如,假设我有 10 名工人和 4 名工人,工人在随机时间预订。我的查询只检查了 BOOKINGS 中的 4 名工人,而忽略了所有尚未找到工作的 WOEKERS。如您所见,这是一个巨大的问题。我如何按照描述查询所有可用的工作人员?我必须通过我的 php 脚本执行逻辑吗?

谢谢大家!!!!!!我知道这是一项复杂的任务,并且需要您花时间阅读。

工作表

CREATE TABLE WORKERS (
            ID INT NOT NULL AUTO_INCREMENT,
            WORKER_NAME  VARCHAR(80) NOT NULL,
            WORKER_CODE  INT, 
            WORKER_WAGE  INT, 
            PRIMARY KEY (ID)
)

预订表

CREATE TABLE BOOKINGS (
            ID INT NOT NULL AUTO_INCREMENT,
            WORKER_NAME  VARCHAR(80) NOT NULL,
            START DATE NOT NULL,
            END DATE NOT NULL,
            CLIENT_NAME VARCHAR(80) NOT NULL,  
            PRIMARY KEY (ID)
)

客户表(虽然不重要)

CREATE TABLE CLIENTS (
            ID INT NOT NULL AUTO_INCREMENT,
            CLIENT_NAME  VARCHAR(80) NOT NULL,
            ADDRESS VARCHAR(100) NOT NULL, 
            PRIMARY KEY (ID)
)

当前查询

SELECT WORKERS.ID, WORKERS.WORKER_NAME, WORKERS.WORKER_CODE, WORKERS.WORKER_WAGE 
FROM WORKERS
INNER JOIN BOOKINGS
ON WORKERS.WORKER_NAME = BOOKINGS.WORKER_NAME
WHERE (START NOT BETWEEN :start AND :end)
ORDER BY WORKERS.ID

PHP 声明

$conn = new PDO("mysql:host=$servername;dbname=$bname", $username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $conn->prepare("SELECT WORKERS.ID, WORKERS.WORKER_NAME, WORKERS.WORKER_CODE, WORKERS.WORKER_WAGE 
FROM WORKERS
INNER JOIN BOOKINGS
ON WORKERS.WORKER_NAME = BOOKINGS.WORKER_NAME
WHERE (START NOT BETWEEN :start AND :end)
ORDER BY WORKERS.ID
");
$stmt->bindParam(':start', $start);
$stmt->bindParam(':end', $end);
$stmt->execute();
$result = $stmt->setFetchMode(PDO::FETCH_ASSOC); 
$workers = $stmt->fetchAll(); 

示例

【问题讨论】:

【参考方案1】:

您可以选择不在给定时间段忙碌的工作人员列表中的所有工作人员。

SELECT * 
FROM WORKERS
WHERE WORKER_NAME NOT IN ( 
    SELECT WORKER_NAME
    FROM BOOKINGS 
    WHERE START BETWEEN :start AND :end
)

【讨论】:

这种情况下最好不要使用NOT IN。见sqlperformance.com/2012/12/t-sql-queries/left-anti-semi-join 为什么不使用 NOT BETWEEN 子查询在选择所有不忙的工作人员之前从预订中选择所有忙碌的工作人员。 因为你想知道这个时间段是否有可用的worker。如果有工人在此期间之外工作,则不会。 虽然这个查询确实显示了正确的输出,但@lovasoa 有一点关于 NOT IN。我会选择他来回答,但你仍然值得加分,感谢你的帮助。【参考方案2】:

您可以选择所有可用的工人:

SELECT * 
FROM WORKERS AS w
WHERE NOT EXISTS ( 
    SELECT 1
    FROM BOOKINGS 
    WHERE START BETWEEN :start AND :end
      AND WORKER_NAME = w.WORKER_NAME
)

【讨论】:

'select 1'的目的是什么? 因为你必须选择一些东西,但在这种情况下你选择什么并不重要。唯一重要的是子查询是否至少返回一行。

以上是关于SQL - 从两个不同的表返回数据的主要内容,如果未能解决你的问题,请参考以下文章

如何使用触发器从两个不同的表中插入数据

SQL查询返回从数组中选择作者的数据[重复]

使用 Linq 合并两个列表,并根据需要从不同的表中添加数据

在 PL\SQL 中设置 SYS_REFCURSOR 以返回数据集

SQL左连接和group_concat返回重复数据

SQL学习之组合查询(UNION)