Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
当返回可变行数时,如何在MySQL中编写if-else查询_Mysql_Sql - Fatal编程技术网

当返回可变行数时,如何在MySQL中编写if-else查询

当返回可变行数时,如何在MySQL中编写if-else查询,mysql,sql,Mysql,Sql,表中有三列: score status No. 1, 2, 1 0, 1, 2 0, 0, 1 我需要这个,来编写一个C风格的伪SQL: rows = empty; rows = "SELECT * FROM `table` WHERE score = 1" if (rows.Count > 0) //at least one row return rows; rows = "SELECT * FROM `table`

表中有三列:

score  status  No.
1,     2,      1
0,     1,      2
0,     0,      1
我需要这个,来编写一个C风格的伪SQL:

rows = empty;

rows = "SELECT * FROM `table` WHERE score = 1"
if (rows.Count > 0) //at least one row
    return rows;

rows = "SELECT * FROM `table` WHERE status = 2"
if (rows.Count > 1) //more than one row 
    return row with MAX(No.) from rows; //ie MAX(No.) where status = 2

 return rows;
我希望我能说清楚。简而言之,从我的表记录中选择分数为1的记录,如果没有这样的记录,则返回状态为2的记录,如果有多条状态为2的记录,则返回最大值为“否”的记录。如果没有状态为2的记录,则返回空记录

如何在一个查询中编写它?这对我来说应该是一次很好的学习经历。否则,我知道如何分解成更小的查询并运行每个查询。我现在不能使用存储过程

Edit:实际上,我的查询将有几个WHERE子句,但在这两个条件中都是相同的,这就是我省略它的原因。因此,关于第一个条件,目前只返回一条记录。也就是说,从score=1的表中选择*现在只返回一行。我需要/我也会接受给出这种解决方案的答案。但问题是,你永远不知道,将来可能会有一些设计更改,可能会有更多的行分数为1。这就是为什么我喜欢唱片而不是唱片。但理想情况下,业务逻辑是拥有分数为1的所有记录。就目前而言,记录就行了。我只是想,如果只返回一行,并且我的队友可以很容易地理解代码,查询就会简单得多

最后更新:谢谢大家,你们一直都很友好:很多答案都很有效,选择一个答案真的很让人畏惧。我对答案的发现:

答案总是有效的:,,最后3个基本相同,但我不完全了解它们是如何工作的:

仅当第一个条件分数=1时有效的答案仅返回一行:。目前,我将继续使用@Danielle's,它异常简单,如果需要多行,稍后将恢复使用

其余的答案,我无法测试,因为它们要么不是很具体,要么与MySQL无关

这在上下文中是不合适的


有这么多正确的答案,授予赏金并接受答案是很困难的。我之所以选择它,是因为我觉得它可能更高效、更可读,但我会接受@Scen的简单性。

完全未经测试,很可能效率很低,但可能有效:

SELECT * FROM `table`
WHERE score=1

union all

SELECT * FROM `table`
WHERE status=2 
and NOT EXISTS (SELECT * FROM `table` WHERE score=1)
and `No.` = (
             SELECT max(`No.`) FROM `table`
             WHERE status=2 
            )

假设在编号中仅使用正整数:

我所做的是创建了一个表达式,行将按该表达式排序。如果分数为1,表达式将返回-2;如果状态为1,表达式将返回-1。作为备用方案,我们将按编号字段按降序排序


请参阅Shlomi Noach的解决方案,了解当No.字段为负值时,该解决方案的改进效果。

此查询将解决您的问题:

SELECT *
  FROM `your_table`
WHERE
  status = 2 OR score = 1 
ORDER BY
  if(score = 1, 1, 0) DESC, 
  if(status = 2, 1, 0) DESC,
  `No.` DESC
LIMIT 1;
与其他答案相反:

它不假定列号为正值。 这是您标记为MySQL的MySQL语法 但是,请放心地将荣誉/声誉归功于KSiimson,他为我们指明了正确的道路。不幸的是,他的查询有两个bug


还要注意的是,所述查询不能利用ORDERBY子句上的任何索引,因为我们用函数包装列。由于OR条件,不太可能在FROM子句上使用索引。

这似乎很难,因为在这两种情况下返回的行数可变

下面的查询组合了所有可能的行,然后检查第一个类型是否存在,以查看应该返回哪种类型

select *
from ((SELECT 'SCORE' as matchtype, t.*
       FROM `table` t
       WHERE score = 1
      ) union all
      (SELECT 'STATUS' as matchtype, t.*
       FROM `table` t join
            (select max(`No.`) as maxno
             from `table` 
             WHERE status = 2
           ) tsum
           on t.`No.` = tsum.maxno
       WHERE status = 2
      )
     ) t cross join
     (select count(*) as cnt
      from `table`
      where score = 1
     ) const
where matchtype = (case when const.cnt > 0 then 'SCORE' else 'STATUS' end)

注意:返回集包括匹配类型。要解决此问题,您需要包含所需列的完整列表。

这里有一个更有效的解决方案,它应该适合您:

SELECT * FROM tbl WHERE score = 1 

UNION ALL

(
    SELECT a.* 
    FROM tbl a
    INNER JOIN
    (
        SELECT COUNT(1) AS s1exists FROM tbl WHERE score = 1
    ) b ON b.s1exists = 0
    WHERE a.status = 2
    ORDER BY a.no DESC
    LIMIT 1
)
细分: 这个查询的工作原理是,联合中的第一个SELECT返回score=1的所有行。第二个选择返回基于no字段的最大行,其中status=2,而score=1则没有一行。无论只有一行还是状态为2的多行,这两行的最大行数都是相同的

这满足您指定的所有条件:

存在一行或多行,其中score=1:First SELECT返回所有这些行;即使存在状态为2的行,second SELECT也返回空。 分数为1的行不存在,状态为2的行存在:First SELECT返回空;第二个SELECT返回一行,该行与max行相同。 分数为1的行不存在,状态为2的行不止一行:First SELECT返回空;第二次选择返回状态为2的最大行。 如果分数=1或状态=2,则根本不存在任何行:第一行不返回任何内容;第二行也不返回任何内容,呈现空结果。
您可以从此查询中获取第一个结果:

-- If there is no row with Score 1, then the first SELECT will return nothing.
-- If there is a row with Score 1, then you will get it.
-- No row with Score 1. If there is one row with Status 2, then you will get it.
-- No row with Score 1. If there is more than one row with Status 2, then you will get the one with the highest No.

SELECT 1 AS ColumnOrder, Table.*
FROM   Table
WHERE  Score = 1
LIMIT  1
UNION ALL
SELECT   2 AS ColumnOrder, Table.* 
FROM     Table 
WHERE    Status=2 
ORDER BY ColumnOrder, No DESC
LIMIT    1 

我留下了我最初的答案,但没有下面的答案那么有效:

/*
Query returns rows with score=1 when they exist or nothing
*/
select score, status, no from temp where score=1

UNION

/*
Query returns rows with status=2 when they exist and when there are no rows
 with score=1 or nothing otherwise.
*/
(

select t1.score, t1.status, t1.no from

( /* <subquery> */

(
select score, status, no from temp
where status=2 and (select max(score) from temp where score=1) is null
) as t1

join

(
select max(no) as maxNo from temp where status=2
) as t2

on t1.no=t2.maxNo

) /* </subquery> */

limit 1

)

原始答复:

/*
Query returns rows with score=1 when they exist or nothing
*/
select score, status, no from temp where score=1

UNION

/*
Query returns nothing when there are rows with score=1,
 rows with status=2 when they exist and when there are no rows with score=1, or
 nothing otherwise.

Does this by adding weights to rows.
Rows with score=1 have greater weights than rows with status=2.
Joins rows with greatest weights to rows with status=2.
*/
( /* <query> */

select t.score, t.status, t.no from
( /* <joins> */

/* Gets greatest weight */
(
select max(if(score=1, 2, if(status=2, 1, -1))) as w
from temp
) as t1

join

/*  Joined on rows with status=2 using assigned weights */
(
select score, status, no, if(score=1, 2, if(status=2, 1, -2)) as w
from temp
where status=2
) as t

on t.w=t1.w

join

/*  Joined on rows with greatest No. for rows with status=2 */
(
select max(no) as maxNo
from temp
where status=2
) as t2

on t.no=t2.maxNo

) limit 1 /* </joins> (Only returns one row with max No.) */

) /* </query> */

我还不能?看到什么优雅的吗 只需一次查询即可解决问题

此外,我不确定你真正的问题是什么;您的示例代码似乎很清楚,但我发现很难从中推断出一个能够满足您需求的问题

我的查询将有几个WHERE子句,但在两个 条件

除此之外,我很惊讶到目前为止还没有人提议使用GROUPBY子句。 这里不讨论MySQL的语法细节,但基本上

select score, status, MAX(No) as No
from tbl 
group by score, status
将为每个“组”精确地提供一条记录,最大值为No

例如,将上面的选择放入子查询中可以细化

select *
from ( [*] ) as tbl
where
   (score = 1)
OR (score != 1 AND status = 2)
OR /* ... more conditions of the above type... */
order by /* ... */
limit 1
[*]表示上面的分组select语句

根据需要添加或删除order by score DESC、status DESC和/或limit 1子句的变体,您应该非常接近您的需要。

这是我的答案,但我将此作为另一个答案发布,因为它在WHERE子句中使用了完全不同的技术条件,而不是使用UNION

IF EXISTS(Select * From `table` Where score = 1)
Begin
    Select * From `table` Where score = 1;
End
Else
Begin
    Select *
    From `table`
    Where status = 2
    Order by `No.` desc
    LIMIT 1
End
这避免了必须使用联合运算符,这可能是您所追求的,即使从技术上讲,使用两条语句的联合算作一个查询。另一个优点是它与DBMS无关,不依赖于ORDER BY X/LIMIT 1,后者主要是一种基于MySQL的技术,用于检索最小行和最大行:

SELECT a.*
FROM tbl a
CROSS JOIN (SELECT COUNT(1) AS score1cnt FROM tbl WHERE score = 1) b
CROSS JOIN (SELECT MAX(no) AS maxno FROM tbl WHERE status = 2) c
WHERE
    CASE WHEN b.score1cnt > 0 THEN a.score = 1
         WHEN b.score1cnt = 0 AND c.maxno IS NOT NULL THEN a.status = 2 AND a.no = c.maxno
         ELSE 0
    END
你可以随便摆弄一本包含我两个答案的书

Select *
From scores
Where score = 1
UNION
(
   Select *
   From scores
   Where status = 2 and not exists (Select * from scores where score = 1)
   Order By `No.` desc
   Limit 1
);
我把这个表命名为分数

SqlFiddle查询带有一些伪模式,因此您可以看到结果:



编辑:编辑SqlFIDLE以将伪模式与问题中的模式匹配。

您的伪代码不起作用。它永远不会到达第二个condition@MatthewPK为什么它达不到?我只是提供了一组示例值。我担心我遗漏了一些关键点?在第一种情况下,您是在查找所有符合条件的行还是只查找一行?好的,太好了!我的解决方案仍然有效。谢谢。@DaveF,仔细看看:如果条件rows.Count>1不满足,底部的最后一个返回将返回第二次查询的结果。如果条件rows.Count>1不满足,它将跳过执行带有MAXno的返回行。。。然后直接返回最后一个返回,返回一行或空结果。如果满足rows.Count>1,它将使用MAXno执行返回行。。。最后一次返回没有执行。你确定mysql支持rank吗?我很感谢你的信任!不幸的是,昨天我在星巴克做这件事——那里的Wifi出现了严重问题,我无法完成编辑查询。我今天早上在工作中完成了它,看到了你的帖子;我喜欢它对分数和状态使用单独的ORDERBY子句,所以即使No.是负数,它也会工作;它可以缩短很多。但它现在的放置方式是我所能做到的最具可读性的。干杯,但现在我从最近对这个问题的评论中看到,作者希望得到所有与score=1匹配的行。所以这个解决方案仍然是不正确的…这修复了我自己的解决方案中的错误,其中只返回一行,只是在后期才进行了澄清。我是mysql的askin。加上1,这是一个非常奇怪的解决方案+100 ; 当然,只有当score=1必须只返回一条记录时,它才有效。但是,这确实是一种很好的看待它的方式,而且是最直接的方式。但不必那么高效。。让我用一些示例测试一下,然后回到UU,很幸运,这不起作用,原因是内部组的行为与mysql的奇怪方式相同。我似乎无法重现内部查询的group by的问题。-你能详细说明一下你得到了什么结果吗?顺便说一句,我已经编辑了我的答案,以便更清楚地说明order by和limit子句只适用于外部查询。汉诺,这不起作用。我不确定我是否能令人信服地说明原因。请参阅此sqlfiddle链接。这里的问题是,查询末尾的limit子句最终决定了应该返回多少行,因此它不能是可变数量的记录。此外,逻辑本身是错误的,'因为OR条件基本上在score=1和score!=1和状态=2。你可以看到更多的链接,我想取消商店程序。这不是吗?也请接受我的编辑,使其与mysql兼容。啊,对不起,我不知道您试图避免存储过程。我对此做了另一个回答。我花了几天的时间试图解决这个问题,就像你在这里做的那样,但我不知道如何正确地连接内部连接。我喜欢这里b对b的微妙解,s1exists=0。。。这是我无法理解的。干得好。与其他答案相比,我更喜欢这个解决方案。是的,我很后悔给另一个答案赏金。我现在觉得这是我应得的。基本上,我在你的两个答案中左右为难,不知怎的,我选择了另一个。我以为是其他人
r的效率更高。你知道你的哪种方法更有效吗?这不是“朱利安”吗到底是什么?此外,在第一次查询中,分数=1的限制1必须做什么?在exists查询中不需要限制1。顺便说一句,您提出这个问题的原因是为了创建一个清晰的查询供其他人使用,对吗?这与@JulienCh的答案并不完全相同,因为语法不同。这是相同的结果,不管怎样,两者最终可能会变成相同的查询。我明白了,很好的意图,但避免相当明显的事情实际上会消除我经验中的困惑。是的,到最后你的问题是不同的,我更喜欢你的问题,但在其他方面都是一样的:我也没有看到他的答案。我看完后投了赞成票P
IF EXISTS(Select * From `table` Where score = 1)
Begin
    Select * From `table` Where score = 1;
End
Else
Begin
    Select *
    From `table`
    Where status = 2
    Order by `No.` desc
    LIMIT 1
End
SELECT a.*
FROM tbl a
CROSS JOIN (SELECT COUNT(1) AS score1cnt FROM tbl WHERE score = 1) b
CROSS JOIN (SELECT MAX(no) AS maxno FROM tbl WHERE status = 2) c
WHERE
    CASE WHEN b.score1cnt > 0 THEN a.score = 1
         WHEN b.score1cnt = 0 AND c.maxno IS NOT NULL THEN a.status = 2 AND a.no = c.maxno
         ELSE 0
    END
Select *
From scores
Where score = 1
UNION
(
   Select *
   From scores
   Where status = 2 and not exists (Select * from scores where score = 1)
   Order By `No.` desc
   Limit 1
);