是否可以使用MySQL

时间:2017-02-21 08:49:24

标签: mysql date search

给出的数据包含一段时间,跨越多年。就像这样:

| 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日还没有活着。我想这很简单,因为它已经是一个字符串匹配。

3 个答案:

答案 0 :(得分:1)

如果您可以修改数据,我建议将其更改为字段Born&如果没有死,那么我们可以使用Born的LEFTINSTR函数以及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)

  

我是否需要在一个字段或两个字段中的日期

绝对是两个,birthdeath,并使用谓词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& endDatebornDate& DeathDate),然后您可以通过这种方式编写查询:

select * from t where YEAR(startDate) >= 1788 OR YEAR(endDate) <= 1788