【问题标题】:Help me rewrite this query帮我重写这个查询
【发布时间】:2010-08-06 20:37:30
【问题描述】:

我有这个问题:

SELECT diamond_id, carat, clarity, color, cut,
    CASE clarity
        WHEN "FL" THEN 0
        WHEN "IF" THEN 1
        WHEN "VVS1" THEN 2
        WHEN "VVS2" THEN 3
        WHEN "VS1" THEN 4
        WHEN "VS2" THEN 5
        WHEN "SI1" THEN 6
        WHEN "SI2" THEN 7
        WHEN "I1" THEN 8
        WHEN "I2" THEN 9
        WHEN "I3" THEN 10
        ELSE -1
    END AS clarity_score,
    CASE cut
        WHEN "ideal" THEN 0
        WHEN "excellent" THEN 1
        WHEN "very good" THEN 2
        WHEN "good" THEN 3
        WHEN "fair" THEN 4
        WHEN "poor" THEN 5
        ELSE -1
    END AS cut_score    
    FROM rapnet_diamonds
 WHERE 
    shape IN ("round","princess","oval") 
 AND (carat BETWEEN ".1" AND "5") 
 AND (color BETWEEN "D" AND "Z") 
 AND (clarity_score BETWEEN "0" AND "10") 
 AND (cut_score BETWEEN "0" AND "5")

如您所见,我动态生成了 clarity_scorecut_score 列,因此我可以在 WHERE 子句中使用它们。

首先,这给了我一个错误,告诉我clarity_score 不存在。所以我想也许这是我需要使用 HAVING 的情况之一?

所以我将 where 子句更改为:

WHERE 
    shape IN ("round","princess","oval") 
 AND (carat BETWEEN ".1" AND "5") 
 AND (color BETWEEN "D" AND "Z") 
HAVING 
    (clarity_score BETWEEN "0" AND "10") 
 AND (cut_score BETWEEN "0" AND "5")

我没有收到错误,但结果为 0... 这应该返回超过 100K。所以我在某处写错了?

然而,在你开始重写之前,我不想选择这两个生成的字段,有没有办法可以编写它,这样我就不会检索这两个字段,只是在 where 子句中使用它们?

【问题讨论】:

    标签: sql mysql select


    【解决方案1】:

    您可以执行以下操作。

    创建两个查找表

    create table clarity_lookup 
        (clarity_score int,
        clarity char(5))
    
    create table cut_lookup 
        (cut_score int,
        cut char(10))
    

    用数据加载查找表

    INSERT INTO clarity_lookup (clarity_score, clarity) VALUES (0, 'FL')
    INSERT INTO clarity_lookup (clarity_score, clarity) VALUES (1, 'IF')
    INSERT INTO clarity_lookup (clarity_score, clarity) VALUES (2, 'VVS1')
    INSERT INTO clarity_lookup (clarity_score, clarity) VALUES (3, 'VVS2')
    INSERT INTO clarity_lookup (clarity_score, clarity) VALUES (4, 'VS1')
    INSERT INTO clarity_lookup (clarity_score, clarity) VALUES (5, 'VS2')
    INSERT INTO clarity_lookup (clarity_score, clarity) VALUES (6, 'SI1')
    INSERT INTO clarity_lookup (clarity_score, clarity) VALUES (7, 'SI2')
    INSERT INTO clarity_lookup (clarity_score, clarity) VALUES (8, 'I1')
    INSERT INTO clarity_lookup (clarity_score, clarity) VALUES (9, 'I2')
    INSERT INTO clarity_lookup (clarity_score, clarity) VALUES (10, 'I3')
    
    INSERT INTO cut_lookup (cut_score, cut) VALUES (0, 'ideal')
    INSERT INTO cut_lookup (cut_score, cut) VALUES (1, 'excellent')
    INSERT INTO cut_lookup (cut_score, cut) VALUES (2, 'very good')
    INSERT INTO cut_lookup (cut_score, cut) VALUES (3, 'good')
    INSERT INTO cut_lookup (cut_score, cut) VALUES (4, 'fair')
    INSERT INTO cut_lookup (cut_score, cut) VALUES (5, 'poor')
    

    您的查询将如下所示。总之,您将根据分数将表示原始CASE 子句中的数据的新表连接到菱形表,但在您的 SELECT 子句中显示描述。

    SELECT rapnet_diamonds.diamond_id, rapnet_diamonds.carat,
        clarity_lookup.clarity, rapnet_diamonds.color, cut_lookup.cut
    FROM rapnet_diamonds
    LEFT OUTER JOIN clarity_lookup ON rapnet_diamonds.clarity_score = clarity_lookup.clarity_score
    LEFT OUTER JOIN cut_lookup ON rapnet_diamonds.cut_score = cut_lookup.cut_score
    WHERE rapnet_diamonds.shape IN ('round','princess','oval') 
        AND (rapnet_diamonds.carat BETWEEN .1 AND 5) 
        AND (rapnet_diamonds.color BETWEEN 'D' AND 'Z') 
        AND (rapnet_diamonds.clarity_score BETWEEN 0 AND 10) 
        AND (rapnet_diamonds.cut_score BETWEEN 0 AND 5)
    

    【讨论】:

    • +1:如果其他地方不需要该信息,可以使用临时表。我要做的唯一改变是使用COALESCE(clarity_lookup.clarity_score, -1)
    【解决方案2】:

    这不起作用吗? (我对 MySQL 的经验有限。)

    SELECT diamond_id, carat, clarity, color, cut
      FROM rapnet_diamonds
     WHERE 
        shape IN ("round","princess","oval") 
     AND (carat BETWEEN ".1" AND "5") 
     AND (color BETWEEN "D" AND "Z") 
     AND (  CASE clarity
            WHEN "FL" THEN 0
            WHEN "IF" THEN 1
            WHEN "VVS1" THEN 2
            WHEN "VVS2" THEN 3
            WHEN "VS1" THEN 4
            WHEN "VS2" THEN 5
            WHEN "SI1" THEN 6
            WHEN "SI2" THEN 7
            WHEN "I1" THEN 8
            WHEN "I2" THEN 9
            WHEN "I3" THEN 10
            ELSE -1
        END BETWEEN "0" AND "10") 
     AND (  CASE cut
            WHEN "ideal" THEN 0
            WHEN "excellent" THEN 1
            WHEN "very good" THEN 2
            WHEN "good" THEN 3
            WHEN "fair" THEN 4
            WHEN "poor" THEN 5
            ELSE -1
        END BETWEEN "0" AND "5")
    

    【讨论】:

      【解决方案3】:

      我会将 case 语句逻辑放入查找解码器表中,然后加入该表。 然后可以使用 where 子句中的列,这样可以简化 SQL。

      类似

      create table ClarityCode
      (
         Clarity char(x) not null
      ,  CodeID int not null
      )
      

      【讨论】:

      • 我认为 Bobs 的回答很好地解释了这一点。如果我不是在星期五急着下班,我会怎么做。
      【解决方案4】:

      为什么不使用 IN?

      SELECT diamond_id, carat, clarity, color, cut
      FROM rapnet_diamonds
      WHERE
      shape IN ("round","princess","oval") AND
      (carat BETWEEN ".1" AND "5") AND
      (color BETWEEN "D" AND "Z") AND
      clarity IN ('FL', 'IF', 'VVS1', 'VVS2', 'VS1', 'VS2', 'SI1', 'SI2', 'I1', 'I2', 'I3') AND
      cut IN ('ideal', 'excellent', 'very good', 'good', 'fair', 'poor')
      

      【讨论】:

      • 这不允许我在“公平”和“优秀”之间做一些事情
      【解决方案5】:

      我会接受您的查询并稍微修改您的代码以使其正常工作

      SELECT * FROM 
        (
          SELECT diamond_id, carat, clarity, color, cut, 
              CASE clarity 
                  WHEN "FL" THEN 0 
                  WHEN "IF" THEN 1 
                  WHEN "VVS1" THEN 2 
                  WHEN "VVS2" THEN 3 
                  WHEN "VS1" THEN 4 
                  WHEN "VS2" THEN 5 
                  WHEN "SI1" THEN 6 
                  WHEN "SI2" THEN 7 
                  WHEN "I1" THEN 8 
                  WHEN "I2" THEN 9 
                  WHEN "I3" THEN 10 
                  ELSE -1 
              END AS clarity_score, 
              CASE cut 
                  WHEN "ideal" THEN 0 
                  WHEN "excellent" THEN 1 
                  WHEN "very good" THEN 2 
                  WHEN "good" THEN 3 
                  WHEN "fair" THEN 4 
                  WHEN "poor" THEN 5 
                  ELSE -1 
              END AS cut_score     
              FROM rapnet_diamonds 
           WHERE  
              shape IN ("round","princess","oval")  
           AND (carat BETWEEN ".1" AND "5")  
           AND (color BETWEEN "D" AND "Z")
      )t 
      WHERE   
           (clarity_score BETWEEN "0" AND "10")  
           AND (cut_score BETWEEN "0" AND "5") 
      

      不能在 where 子句中使用大小写变量

      【讨论】:

        【解决方案6】:

        为了回应对拆分表想法的更多解释:

        不是将所有内容都放在CASE 语句中,而是将清晰度信息存储在第二个表中。它可能看起来像这样:

        Clarity_Table
        -----------------------
        Clarity_score | clarity
        -----------------------
        0             | FL
        1             | IF
        2             | VVS1
        3             | VVS2
        4             | VS1
        5             | VS2
        ...
        10            | I3
        

        Cut_Table 也是如此,希望你能从上面得到这个想法。

        然后,将您的查询更改为:

        SELECT diamond_id, carat, clarity, color, cut, clarity_score, cut_score    
            FROM rapnet_diamonds JOIN clarity_table USING(clarity)
                                 JOIN cut_table USING(cut)
         WHERE 
            shape IN ("round","princess","oval") 
         AND (carat BETWEEN ".1" AND "5") 
         AND (color BETWEEN "D" AND "Z") 
         AND (clarity_score BETWEEN "0" AND "10") 
         AND (cut_score BETWEEN "0" AND "5")
        

        然后,它不是对分数进行硬编码,而是在表之间进行连接。我怀疑它会经常更新,但它会使以后的更改变得更容易,并使整体代码的维护和可读性变得更加容易。

        【讨论】:

          猜你喜欢
          • 2011-11-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多