美好的一天。
我似乎正在努力解决看似简单的问题。
我有一个表格,其值与有限数量的ID的日期(每月)相关
即。表1
ID | Date ---| Value
01 | 2015-01 | val1
01 | 2015-02 | val2
02 | 2015-01 | val1
02 | 2015-03 | val2
因此ID:02没有2015-02日期的值。
我想返回没有值的所有ID和日期。 日期范围是:从表1中选择不同的日期
我似乎无法在选择和加入同一桌面之外思考。
我需要在我的选择中包含ID,我可以以某种方式选择该ID存在的ID和日期范围,并与整个日期范围进行比较,以获取不在“ID”中的每个ID的所有日期整个“日期范围。
请指教。 谢谢
答案 0 :(得分:0)
你的最后两句话不太清楚。但是您可以使用不同的@max_days和@min_date来播放以下查询:
-- DROP TABLE table1;
CREATE TABLE table1(ID int not null, `date` date not null, value varchar(64) not null);
INSERT table1(ID,`date`,value)
VALUES (1,'2015-01-01','v1'),(1,'2015-01-02','v2'),(2,'2015-01-01','v1'),(2,'2015-01-03','v2'),(4,'2015-01-01','v1'),(4,'2015-01-04','v2');
SELECT * FROM table1;
SET @day=0;
SET @max_days=5;
SET @min_date='2015-01-01';
SELECT i.ID,d.`date`
FROM (SELECT DISTINCT ID FROM table1) i
CROSS JOIN (
SELECT TIMESTAMPADD(DAY,@day,@min_date) AS `date`,@day:=@day+1 AS day_num
FROM table1 WHERE @day<@max_days) d
LEFT JOIN table1 t
ON t.ID=i.ID
AND t.`date`=d.`date`
WHERE t.`date` IS NULL
ORDER BY i.ID,d.`date`;
答案 1 :(得分:0)
我现在明白你要求从表中提取日期;您想在每个ID 的日期范围中找到任何空白。
这可以满足您的需求,但可以改进。下面的说明,您可以查看working example。
DROP TABLE IF EXISTS Table1;
DROP TABLE IF EXISTS Year_Month_Calendar;
CREATE TABLE Table1 (
id INTEGER
,date CHAR(7)
,value CHAR(4)
);
INSERT INTO Table1
VALUES
(1,'2015-01','val1')
,(1,'2015-02','val2')
,(2,'2015-01','val1')
,(2,'2015-03','val1');
CREATE TABLE Year_Month_Calendar (
date CHAR(10)
);
INSERT INTO Year_Month_Calendar
VALUES
('2015-01')
,('2015-02')
,('2015-03');
SELECT ID_Year_Month.id, ID_Year_Month.date, Table1.id, Table1.date
FROM (
SELECT Distinct_ID.id, Year_Month_Calendar.date
FROM Year_Month_Calendar
CROSS JOIN
( SELECT DISTINCT id FROM Table1 ) AS Distinct_ID
WHERE Year_Month_Calendar.date >= (SELECT MIN(date) FROM Table1 WHERE id=Distinct_ID.ID)
AND Year_Month_Calendar.date <= (SELECT MAX(date) FROM Table1 WHERE id=Distinct_ID.ID)
) AS ID_Year_Month
LEFT JOIN Table1
ON ID_Year_Month.id = Table1.id AND ID_Year_Month.date = Table1.date
-- WHERE Table1.id IS NULL
ORDER BY ID_Year_Month.id, ID_Year_Month.date
您需要一个日历表,其中包含所有日期(年/月),以涵盖您要查询的数据。
CREATE TABLE Year_Month_Calendar (
date CHAR(10)
);
INSERT INTO Year_Month_Calendar
VALUES
('2015-01')
,('2015-02')
,('2015-03');
内部选择会创建一个表格,其中包含每个id
的最小和最大日期之间的所有日期。
SELECT Distinct_ID.id, Year_Month_Calendar.date
FROM Year_Month_Calendar
CROSS JOIN
( SELECT DISTINCT id FROM Table1 ) AS Distinct_ID
WHERE Year_Month_Calendar.date >= (SELECT MIN(date) FROM Table1 WHERE id=Distinct_ID.ID)
AND Year_Month_Calendar.date <= (SELECT MAX(date) FROM Table1 WHERE id=Distinct_ID.ID)
然后LEFT JOINED
到原始表以查找缺失的行。
如果您只想返回缺失的行(我的查询显示整个表以显示它的工作原理),请添加WHERE
子句以将输出限制为id
和{表1中未返回{1}}
您可以在没有计数表的情况下执行此操作,因为您说
日期范围是:从Table1中选择不同的日期
我稍微更改了字段名称以避免SQL中的保留字。
date
我没有过滤结果,以显示查询是如何工作的。要返回仅缺少日期的行,请将SELECT id_table.ID, date_table.`year_month`, table1.val
FROM (SELECT DISTINCT ID FROM table1) AS id_table
CROSS JOIN
(SELECT DISTINCT `year_month` FROM table1) AS date_table
LEFT JOIN table1
ON table1.ID=id_table.ID AND table1.`year_month` = date_table.`year_month`
ORDER BY id_table.ID
添加到外部查询。
答案 2 :(得分:-1)
您需要一个计数表或月/年表。因此,您可以生成要测试的所有潜在组合。至于如何使用它你的例子可以使用一些扩展,例如过去12个月,过去3个月等等。但这里有一个例子可以帮助你理解你在寻找:
CREATE TABLE IF NOT EXISTS Tbl (
ID INTEGER
,Date VARCHAR(10)
,Value VARCHAR(10)
);
INSERT INTO Tbl VALUES
(1,'2015-01','val1')
,(1,'2015-02','val2')
,(2,'2015-01','val1')
,(2,'2015-03','val1');
SELECT yr.YearNumber, mn.MonthNumber, i.Id
FROM
(
SELECT 2016 as YearNumber
UNION SELECT 2015
) yr
CROSS JOIN (
SELECT 1 MonthNumber
UNION SELECT 2
UNION SELECT 3
UNION SELECT 4
UNION SELECT 5
UNION SELECT 6
UNION SELECT 7
UNION SELECT 8
UNION SELECT 9
UNION SELECT 10
UNION SELECT 11
UNION SELECT 12
) mn
CROSS JOIN (
SELECT DISTINCT ID
FROM
Tbl
) i
LEFT JOIN Tbl t
ON yr.YearNumber = CAST(LEFT(t.Date,4) as UNSIGNED)
AND mn.MonthNumber = CAST(RIGHT(t.Date,2) AS UNSIGNED)
AND i.ID = t.ID
WHERE
t.ID IS NULL
确定你不知道的基本想法是生成所有可能的组合。例如。年X月X DISTINCT Id,然后再加入以找出遗漏的内容。
答案 3 :(得分:-1)
可能不是最漂亮的,但这应该有用。
select distinct c.ID, c.Date, d.Value
from (select a.ID, b.Date
from (select distinct ID from Table1) as a, (select distinct Date from Table1) as b) as c
left outer join Table1 d on (c.ID = d.ID and c.Date = d.Date)
where d.Value is NULL