mysql 在结果中标记查询的匹配类型,而不运行两次子查询

6kkfgxo0  于 2023-04-19  发布在  Mysql
关注(0)|答案(2)|浏览(126)

我有一个复杂的查询。下面是我想做的最基本的例子。

SELECT 
  match_by_color AS match_type,
  t1.*
FROM t1 
WHERE 
  ( t1.color LIKE 'color%') -- match_by_color
  OR (t1.type in (select type from t2)) -- match_by_type
  OR (t1.name in (select name from t3 WHERE ...)) -- match_by_name
  OR (t1.age in (select age from t4 WHERE ...)) -- match_by_age

我有3-4个匹配记录的条件。如果它匹配其中一个条件,我想识别第一个匹配类型,而不需要再次运行子查询。我可以这样做,但我觉得它会运行相同的查询两次。

-- I could do this but it would be running the conditional sub queries twice
(
 CASE
   WHEN ( t1.color LIKE 'color%') THEN match_by_color
   WHEN (t1.type in (select type from t2)) THEN match_by_color
   WHEN (t1.name in (select name from t3 WHERE ...)) THEN match_by_name
   WHEN (t1.age in (select age from t4 WHERE ...)) THEN match_by_age
   ELSE no_match
 END
) AS match_type
oyjwcjzk

oyjwcjzk1#

试试这个,我遵循@nbk的建议,我也删除了所有的where子句来简化,我想这样会表现得更好。

;WITH 
  match_by_type AS (
    SELECT type FROM t2
  ),
  match_by_name AS (
    SELECT name FROM t3 WHERE ...
  ),
  match_by_age AS (
    SELECT age FROM t4 WHERE ...
  )

SELECT *
FROM (
  SELECT 
    CASE
      WHEN (t1.color LIKE 'color%') THEN 'match_by_color'
      WHEN (t1.type IN (SELECT type FROM match_by_type)) THEN 'match_by_type'
      WHEN (t1.name IN (SELECT name FROM match_by_name)) THEN 'match_by_name'
      WHEN (t1.age IN (SELECT age FROM match_by_age)) THEN 'match_by_age'
      ELSE 'no_match'
    END AS match_type,
    t1.*
  FROM t1 
) subquery
WHERE 
  subquery.match_type <> 'no_match'
a14dhokn

a14dhokn2#

关于“复杂查询”的问题过于简单化的问题是我们没有意识到复杂性,这将不可避免地对处理查询的最佳方式产生影响。
如果t1t2t3t4之间的关系返回0或1行,则值得测试LEFT JOIN

SELECT 
    CASE
        WHEN t1.color LIKE 'color%' THEN 'match_by_color'
        WHEN t2.type IS NOT NULL THEN 'match_by_type'
        WHEN t3.name IS NOT NULL THEN 'match_by_name'
        WHEN t4.age  IS NOT NULL THEN 'match_by_age'
    END AS match_type,
    t1.*
FROM t1
LEFT JOIN t2 ON t1.type = t2.type
LEFT JOIN t3 ON t1.name = t3.name -- add rest of join criteria here
LEFT JOIN t4 ON t1.age  = t4.age  -- add rest of join criteria here
WHERE t1.color LIKE 'color%' -- match_by_color
   OR t2.type IS NOT NULL    -- match_by_type
   OR t3.name IS NOT NULL    -- match_by_name
   OR t4.age  IS NOT NULL    -- match_by_age
;

如果关系可能返回多行,请尝试使用EXISTS(...)

SELECT 
    CASE
        WHEN t1.color LIKE 'color%' THEN 'match_by_color'
        WHEN EXISTS(SELECT 1 FROM t2 WHERE type = t1.type) THEN 'match_by_type'
        WHEN EXISTS(SELECT 1 FROM t3 WHERE name = t1.name) THEN 'match_by_name'
        WHEN EXISTS(SELECT 1 FROM t4 WHERE age  = t1.age ) THEN 'match_by_age'
    END AS match_type,
    t1.*
FROM t1 
WHERE t1.color LIKE 'color%' -- match_by_color
   OR EXISTS(SELECT 1 FROM t2 WHERE type = t1.type) -- match_by_type
   OR EXISTS(SELECT 1 FROM t3 WHERE name = t1.name) -- match_by_name
   OR EXISTS(SELECT 1 FROM t4 WHERE age  = t1.age ) -- match_by_age
;

相关问题