【问题标题】:Can I refactor my MySQL queries into one query based on number of results?我可以根据结果的数量将我的 MySQL 查询重构为一个查询吗?
【发布时间】:2010-09-11 14:50:41
【问题描述】:

我有一张表 y 有两列 ab

条目是:

a   b

1   2

1   3

1   4

0   5

0   2

0   4

如果我在 a 列中搜索 1,我想获得 2、3、4,如果我在 a 列中搜索,我想获得 5、2、4。

因此,如果我在 A 中搜索 A 中的某些内容,(1) 我会得到这些行,如果给定值没有条目 A,则给我“默认值”(a = '0')

我知道该怎么做:

$r = mysql_query('SELECT `b` FROM `y` WHERE `a` = \'1\';');
//This gives desired results, 3 rows

$r = mysql_query('SELECT `b` FROM `y` WHERE `a` = \'2\';');
//This does not give desired results yet.
//Get the number of rows, and then get the 'defaults'
if(mysql_num_rows($r) === 0) $r = mysql_query('SELECT `b` FROM `y` WHERE `a` = 0;');

那么,既然已经充分解释了,我该如何在一个查询中做到这一点,以及性能问题呢?

最常用的部分是第三个查询,因为如果您偏离默认值,a 中只会有一个数字的值。

【问题讨论】:

    标签: php sql mysql


    【解决方案1】:

    我想我有它:

    SELECT b FROM y where a=if(@value IN (select a from y group by a),@value,0);
    

    它检查表中是否存在@value,如果不存在,则使用0作为默认值。 @value 也可以是 php 值。

    希望对你有帮助:)

    【讨论】:

    • 我之所以选择这个是因为它只有一个IF,另一个是case,所以由于我只在两个项目之间进行选择,这似乎只是稍微正确一点。
    【解决方案2】:

    你可以试试这样的。我不能 100% 确定它会起作用,因为 count() 是一个聚合函数,但值得一试。

    SELECT b
    FROM table1 
    WHERE a = (
       SELECT
         CASE count(b)
           WHEN 0 THEN :default_value
           ELSE :passed_value 
         END
       FROM table1
       WHERE a = :passed_value
    )
    

    【讨论】:

    • 我想我不能接受两个答案,但是这两个答案都是正确的,我测试了它们,并且尽我所能对它们都投了赞成票。
    【解决方案3】:

    怎么样

    $rows = $db->fetchAll('select a, b FROM y WHERE a IN (2, 0) ORDER BY a DESC');
    if(count($rows) > 0) {
      $a = $rows[0]['a'];
      $i = 0;
      while($rows[$i]['a'] === $a) {
        echo $rows[$i++]['b']."\n";
      }
    }
    

    一个查询,但如果有很多“零”值,则会产生开销。
    取决于您是否关心开销...

    【讨论】:

      【解决方案4】:

      我认为 Michal Kralik 是基于服务器性能的最佳答案。为如此简单的逻辑做子选择或存储过程真的不值得。

      我改进 Michal 逻辑的唯一方法是,如果您在一个脚本中多次执行此查询。在这种情况下,我会先查询 0,然后运行每个单独的查询,然后检查是否有任何值。

      伪代码

      // get the value for hte zero's
      $zeros = $db->fetchAll('select a, b FROM y WHERE a = 0');
      
      //checking for 1's
      $ones = $db->fetchAll('select a, b FROM y WHERE a = 1');
      if(empty($ones)) $ones = $zeros;
      
      //checking for 2's
      $twos = $db->fetchAll('select a, b FROM y WHERE a = 2');
      if(empty($twos)) $twos = $zeros;
      
      //checking for 3's
      $threes = $db->fetchAll('select a, b FROM y WHERE a = 3');
      if(empty($threes)) $threes = $zeros;
      

      【讨论】:

        【解决方案5】:

        您可以使用单个参数在单个存储过程中完成所有这些操作。

        我必须用完,但我会尝试为您写一个,并在我完成差事后立即添加到这里。

        【讨论】:

        • 太棒了。在存储过程方面,我完全无能为力。一般来说,我只会问在存储过程中执行它是否会比我上面建议的 php 版本更好。我的直觉会说'是的,如果数据库在不同的服务器上,否则不是'..
        • 存储过程总是更好。其他人给出的解决方案很好,但是是的,一般来说,向数据库发送尽可能多的信息以返回尽可能少的信息通常是好的,如果客户端是单独的机器真的没关系比服务器
        【解决方案6】:

        我不知道为什么这被标记了 - 请教育我。这是一个有效的、经过测试的存储过程,我回答了这个问题。 OP 不要求答案在 php.ini 中。 ??

        这是一个存储过程,可以在 SQL Server 中执行您想要的工作。我不确定 MySQL。

        create proc GetRealElseGetDefault (@key as int)
        as
        begin
        
        -- Use this default if the correct data is not found
        declare @default int
        select @default = 0
        
        -- See if the desired data exists, and if so, get it.  
        -- Otherwise, get defaults.
        if exists (select * from TableY where a = @key)
            select b from TableY where a = @key
        else
            select b from TableY where a = @default
        
        end -- GetRealElseGetDefault
        

        你可以用

        运行这个(在 sql server 中)

        GetRealElseGetDefault 1

        基于快速的谷歌搜索,MySQL 中的存在速度很快。如果 A 列被索引,它会特别快。如果您的表大到足以让您担心性能,那么它可能大到可以索引。

        【讨论】:

        • 我不知道为什么这被标记了 - 请教育我。这是一个有效的、经过测试的存储过程,我回答了这个问题。 OP 不要求答案在 php.ini 中。 ??
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-02-17
        • 1970-01-01
        • 2012-08-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-06
        相关资源
        最近更新 更多