sql-server - SQL 查询 - 给定两个日期,重复一个表的记录
问题描述
我需要查询
我有两个表,TableA 和 TableB
表A如下:
ID | 姓名 |
---|---|
1 | 车 |
2 | 飞机 |
3 | 船 |
4 | 自行车 |
5 | 滑冰 |
我的 TableB 如下所示:
ID | 我的约会 | FID |
---|---|---|
1 | 29-08-2021 | 1 |
2 | 29-08-2021 | 2 |
3 | 29-08-2021 | 3 |
4 | 30-08-2021 | 1 |
5 | 30-08-2021 | 5 |
FID:是将 TableB 与 TableA 相关联的列。
因此,我需要显示 TableA 的每条记录,以及 TableB 的记录。
我知道如何用一个日期来做到这一点。有些像这样:
SELECT ID, NAME, MyDATE
FROM TableA
LEFT JOIN TableB ON FID = ID AND MyDate = SomeDate
ORDER BY ID
如果 SomeDate = '29-08-2021'
该查询应返回以下结果:
ID | 姓名 | 我的约会 |
---|---|---|
1 | 车 | 29-08-2021 |
2 | 飞机 | 29-08-2021 |
3 | 船 | 29-08-2021 |
4 | 自行车 | 无效的 |
5 | 滑冰 | 无效的 |
如果 SomeDate = '30-08-2021',它应该显示如下
ID | 姓名 | 我的约会 |
---|---|---|
1 | 车 | 30-08-2021 |
2 | 飞机 | 无效的 |
3 | 船 | 无效的 |
4 | 自行车 | 无效的 |
5 | 滑冰 | 30-08-2021 |
所以,我需要的是给出两个日期,并打印该日期范围内的所有内容,TableA 的所有记录及其对应的 TableB 记录
因此,如果我将日期 28-08-2021 指定为 30-08-2021,结果应如下所示
ID | 姓名 | 我的约会 |
---|---|---|
1 | 车 | 无效的 |
2 | 飞机 | 无效的 |
3 | 船 | 无效的 |
4 | 自行车 | 无效的 |
5 | 滑冰 | 无效的 |
1 | 车 | 29-08-2021 |
2 | 飞机 | 29-08-2021 |
3 | 船 | 29-08-2021 |
4 | 自行车 | 无效的 |
5 | 滑冰 | 无效的 |
1 | 车 | 30-08-2021 |
2 | 飞机 | 无效的 |
3 | 船 | 无效的 |
4 | 自行车 | 无效的 |
5 | 滑冰 | 30-08-2021 |
我需要进行一个返回此结果集的查询。
前5条记录,是28-09-2021对应的记录,因为TableB中没有那个日期的记录,所以返回null。
因为有三个日期,所以应该将表 A 的所有记录重复 3 次。
我试着这样做
SELECT ID, NAME, MyDATE
FROM TableA
LEFT JOIN TableB ON FID = ID AND MyDate BETWEEN StartDate AND EndDate
ORDER BY ID
但这样做只会返回 5 条记录(前 3 条记录的日期为 29-08-2021,第二条记录的日期为 30-08-201)。
我需要知道如何执行返回我提供的结果集的查询。
解决方案
您似乎想要做的是获取 TableA 的笛卡尔积,其中包含日期范围内的所有日期。然后在每一行上添加信息,以确定您的 TableB 中是否有相应的行。
您可以从一个简单的递归 SQL 开始,它会获取您的日期:
WITH cte_dates(theDates)
AS (
SELECT @startdate
UNION ALL
SELECT DATEADD(day, 1, thedates)
FROM cte_dates
WHERE thedates < @enddate
)
SELECT *
FROM cte_dates;
这将导致:
日期 |
---|
2021-08-28 |
2021-08-29 |
2021-08-30 |
变量声明如下:
DECLARE @startdate DATE;
DECLARE @enddate DATE;
SET @startdate = '2021-08-28';
SET @enddate = '2021-08-30';
然后将其与您的 TableA 一起使用WHERE 1 = 1
以获取笛卡尔积:
WITH cte_dates(thedates)
AS (
SELECT @startdate
UNION ALL
SELECT DATEADD(day, 1, thedates)
FROM cte_dates
WHERE thedates < @enddate
)
SELECT *
FROM TableA
JOIN cte_dates ON (1 = 1)
;
这将为您提供 15 行,其中 TableA 中的每一行都有一个带有日期的额外列。TableA 中的每个原始行将在此结果集中产生 3 行,因为有 3 个日期。
现在您可以使用外部左连接来获取相应的 TableB 值:
WITH cte_dates(thedates)
AS (
SELECT @startdate
UNION ALL
SELECT DATEADD(day, 1, thedates)
FROM cte_dates
WHERE thedates < @enddate
)
SELECT ta.id, ta.name, tb.mydate
FROM TableA AS ta
JOIN cte_dates AS dat ON (1 = 1)
LEFT JOIN TableB AS tb ON tb.fid = ta.id
AND tb.mydate = dat.thedates
;
推荐阅读
- react-native - 从 react-native 在浏览器中打开非标准协议 url
- python - 将 OpenCV 图像从 C++ 发送到 Python 错误
- ffmpeg - FFmpeg - 如何将原始屏幕缓冲区(帧数组)编码为比特流?
- vb.net - Option Strict 导致 LINQ 语句中的编译错误(隐式转换“对象”到“控制”)
- android - Firebase Firestore E/RecyclerView:未连接适配器;跳过布局火力基地
- sql - Oracle:如何使用更新 sql 语句中的变量在 sql 中设置值
- python - 一次移动一个文件
- javascript - 在输入 AJAX 和 PHP 时显示搜索结果
- javascript - Javascript无法在获取后读取未定义的属性'forEach'
- c# - C# & MS Access - SQL 用于在应用程序开始时创建表、列和添加值