数据类似于下表:
| id | e_date | e_time | place | person| ref |ref_type|
| 10 | 2015-08-03 | 10:30 | work | tony | 1234 | A |
| 25 | 2015-08-03 | 10:30 | work | NULL | NULL | A |
| 37 | 2015-08-03 | NULL | work | tony | NULL | A |
| 99 | 2015-08-03 | 10:30 | work | fred | 1234 | B |
在MySQL WHERE
子句中获取 一系列条件(具有重要性)的第一个匹配的最佳方法是什么? ?
ref
字段ref
字段中没有匹配项,则匹配e_date+e_time+place
字段ref
或e_date+e_time+place
上没有匹配,则匹配e_date+place+person
这里的目标是根据一系列降序标准获得最佳的单行匹配 - 如果前面的标准未得到满足,则仅使用标准。
我对查询的第一次尝试看起来像是:
SELECT id FROM my_table
WHERE ref_type = 'A' AND (
ref = '1234'
OR
(e_date = '2015-08-03' AND e_time = '10:30' AND place = 'work')
OR
(e_date = '2015-08-03' AND place = 'work' AND person = 'tony')
)
但由于OR
包含(不是顺序),因此会返回行10
,25
和37
- 请参阅this sqlfiddle
我可以ORDER BY ref DESC
和LIMIT 1
(如果我修改为SELECT id, ref FROM...
)但如果我没有ref
值并且必须区分,那对我没有帮助通过第二或第三个条件
我的下一次尝试使用IF
子句中的嵌套WHERE
条件,如:
SELECT id FROM my_table
WHERE ref_type = 'A' AND (
IF(ref = 1234,
ref = 1234,
IF(e_date = '2015-08-03' AND e_time = '10:30' AND place = 'work',
e_date = '2015-08-03' AND e_time = '10:30' AND place = 'work',
e_date = '2015-08-03' AND place = 'work' AND person = 'tony'
)
)
)
但是,这也会返回行10
,25
和37
- 请参阅this sqlfiddle
还尝试使用IFNULL
:
SELECT id FROM my_table
WHERE ref_type = 'A' AND
IFNULL(ref = '1234',
IFNULL(e_date = '2015-08-03' AND e_time = '10:30' AND place = 'work',
e_date = '2015-08-03' AND place = 'work' AND person = 'tony')
)
返回行10
和25
- 请参阅this sqlfiddle
编写此查询的最佳方法是什么?
我使用php - 我可以运行3个单独的顺序查询并在每个结果上使用php条件 - 但我想使用单个数据库查询,因为数百万次运行此代码每小时。
答案 0 :(得分:2)
唯一的方法(我知道)是使用不同的where
多次运行查询。您可以使用union来执行单个查询:
SELECT * FROM (
SELECT <stuff> FROM <table> WHERE <most important condition> LIMIT 1
UNION
SELECT <stuff> FROM <table> WHERE <less important condition> LIMIT 1
UNION
SELECT <stuff> FROM <table> WHERE <even less important condition> LIMIT 1
UNION
...
) as t
LIMIT 1
或者您可以逐个运行它们,如果有结果则停止。
答案 1 :(得分:0)
试试这个:
SELECT
id
FROM my_table
WHERE ref_type = 'A'
ORDER BY
(CASE WHEN ref = '1234'
THEN 1
ELSE
(CASE WHEN e_date = '2015-08-03' AND e_time = '10:30' AND place = 'work'
THEN 2
ELSE
(CASE WHEN (e_date = '2015-08-03' AND place = 'work' AND person = 'tony')
THEN 3
ELSE 4
END)
END)
END)
LIMIT 1
或者,如果运行时间较长,请使用以下查询创建视图:
SELECT
id,
(CASE WHEN ref = '1234'
THEN 1
ELSE
(CASE WHEN e_date = '2015-08-03' AND e_time = '10:30' AND place = 'work'
THEN 2
ELSE
(CASE WHEN (e_date = '2015-08-03' AND place = 'work' AND person = 'tony')
THEN 3
ELSE 4
END)
END)
END) AS "case_field"
FROM my_table
WHERE ref_type = 'A'
然后运行:
SELECT id FROM your_view ORDER BY case_field LIMIT 1;
答案 2 :(得分:0)
如果我理解了你的逻辑,你想要返回ref
行,如果它不是空的话。如果它为null,那么e_time
的那个不为空。最后,person
的那个不为空。那么,也许你可以将这个排序用于你的第一次尝试查询?
SELECT id FROM my_table
WHERE ref_type = 'A' AND (
ref = '1234'
OR
(e_date = '2015-08-03' AND e_time = '10:30' AND place = 'work')
OR
(e_date = '2015-08-03' AND place = 'work' AND person = 'tony')
)
ORDER BY ref DESC,
e_time DESC,
person DESC
LIMIT 1 ;
答案 3 :(得分:0)
你应该在何处尝试案例,
SELECT id FROM my_table
WHERE
1 = case when ref_type = 'A' then 1
else
case when ref = '1234' then 1
else
case when (e_date = '2015-08-03' AND e_time = '10:30' AND place = 'work') or (e_date = '2015-08-03' AND place = 'work' AND person = 'tony') then 1 else 0 end
end
end
如果符合标准的任何一个条件,它将以递增的方式检查条件,然后它不会检查更多。
不确定您的确切条件,以便在此处作为参考,您应该使用这种方式来满足您的需求。