给出的数据包含一段时间,跨越多年。就像这样:
| ID | Name | Alive |
|----|--------------------|-----------------------|
| 1 | Washington, George | 1732-02-22/1799-12-14 |
| 2 | Adams, John | 1735-10-30/1826-07-04 |
| 3 | Jefferson, Thomas | 1743-04-13/1826-07-04 |
…
是否可以将这些数据存储在MySQL中,以便搜索中间日期(所有字段,仅一年),如搜索字词1788
,会产生结果?
我正在寻找的是这样的:
CREATE TABLE t (
id INT NOT NULL,
name VARCHAR(30),
alive DATERANGE
);
SELECT * FROM t WHERE * LIKE '%1788%'
我看到的唯一解决方案是添加另一个包含年份列表的列,(1732,1733,
...)但我想有更好的解决方案。我需要一个字段或两个字段中的日期,我需要什么样的列类型才能工作?我可以在该列的指定日期范围内(例如1155/1227
)或者我必须在插入之前重写它们(例如1155-01-01/1227-12-31
)吗?
也应退回边境比赛。搜索字符串1799
仍应返回乔治华盛顿,即使他从1月1日到12月31日还没有活着。我想这很简单,因为它已经是一个字符串匹配。
答案 0 :(得分:1)
如果您可以修改数据,我建议将其更改为字段Born&如果没有死,那么我们可以使用Born的LEFT
和INSTR
函数以及Died的SUBSTRING_INDEX
函数。
SELECT ID, Name, Alive,
LEFT([ColName],INSTR([Alive],"/")-1) AS Born,
SUBSTRING_INDEX(Alive,'/',-1) AS Died
FROM t
哪个会分出Born和Died日期:
| ID | Name | Alive | Born | Died |
|----|--------------------|-----------------------|------------|------------|
| 1 | Washington, George | 1732-02-22/1799-12-14 | 1732-02-22 | 1799-12-14 |
| 2 | Adams, John | 1735-10-30/1826-07-04 | 1735-10-30 | 1826-07-04 |
| 3 | Jefferson, Thomas | 1743-04-13/1826-07-04 | 1743-04-13 | 1826-07-04 |
然后你可以使用:
WHERE Alive LIKE '%1788%'
搜索日期。
或者单独出生:
WHERE LEFT([ColName],INSTR([Alive],"/")-1) LIKE '%1788%'
死于
WHERE SUBSTRING_INDEX(Alive,'/',-1) LIKE '%1788%'
或者如果您只是想在Born和Died字段中使用额外的LEFT
函数:
SELECT ID, Name, Alive,
LEFT(LEFT([ColName],INSTR([Alive],"/")-1),4) AS Born,
LEFT(SUBSTRING_INDEX(Alive,'/',-1),4) AS Died
FROM t
哪会给你:
| ID | Name | Alive | Born | Died |
|----|--------------------|-----------------------|------|------|
| 1 | Washington, George | 1732-02-22/1799-12-14 | 1732 | 1799 |
| 2 | Adams, John | 1735-10-30/1826-07-04 | 1735 | 1826 |
| 3 | Jefferson, Thomas | 1743-04-13/1826-07-04 | 1743 | 1826 |
编辑:
你可以反过来使用BETWEEN
功能。
SELECT ID, Name, Alive,
LEFT(LEFT([ColName],INSTR([Alive],"/")-1),4) AS Born,
LEFT(SUBSTRING_INDEX(Alive,'/',-1),4) AS Died
FROM t
WHERE 1788 BETWEEN LEFT(LEFT([ColName],INSTR([Alive],"/")-1),4) AND LEFT(SUBSTRING_INDEX(Alive,'/',-1),4)
答案 1 :(得分:1)
我是否需要在一个字段或两个字段中的日期
绝对是两个,birth
和death
,并使用谓词BETWEEN ... AND ...
进行搜索。它比在每个查询中拆分两个字段要便宜,它可以更好地利用索引。
我需要什么样的列类型
那太棘手了。我通常肯定会同意评论说你必须使用date
字段,出于各种众所周知的充分理由。但是,从您的问题中可以明显看出,您只对数年感兴趣并且实际上无视实际日期;此外,您正在处理可能不完整的历史数据:在这种情况下,通常会缺少几天甚至几个月;这些不完整的日期可以存储在date
字段中,但会对某些操作返回NULL
,这可能会产生问题;如果您有date
字段,则无法在年份上创建索引,因此您的查询都将是全表扫描。简而言之,在您的特定情况中,我会使用SMALLINT UNSIGNED
这些年来CHAR(5)
来存储不太有用的日常信息,以防万一你将来可能需要它,用CAST(CONCAT(year,'-', month_and_day) AS DATE)
动态建立一个真实的日期。
总之,这是我提出的设计:
CREATE TABLE t (
id INT NOT NULL,
name VARCHAR(30),
birth_year SMALLINT UNSIGNED,
birth_md CHAR(5),
death_year SMALLINT UNSIGNED,
death_md CHAR(5)
);
CREATE INDEX t_ndx ON t(birth_year, death_year);
SELECT * FROM t WHERE 1788 BETWEEN birth_year AND death_year;
答案 2 :(得分:1)
与@CBroe建议一样 - 您应该有两列(startDate
& endDate
或bornDate
& DeathDate
),然后您可以通过这种方式编写查询:
select * from t where YEAR(startDate) >= 1788 OR YEAR(endDate) <= 1788