我在表格中有三列:
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,如果没有这样的记录,则返回status = 2的记录,如果有多个记录,状态= 2,则返回最大值的记录如果状态= 2,则为否(如果状态= 2,则根本没有记录,则返回空)。
如何在一个查询中编写它?对我来说这应该是一个很好的学习经历。否则我知道要分解成较小的查询并运行每个查询。我现在不能使用存储过程..
编辑:实际上我的查询会有一些WHERE子句但在两个条件中都相同,这就是我省略它的原因。因此,关于第一个条件,现在只返回一条记录。那就是SELECT * FROM table WHERE score = 1
现在只返回一行。并且我需要/我会接受答案,这也提供了这样的解决方案。但关键是你永远不知道,未来可能会有一些设计更改,可能会有更多行score = 1
。这就是为什么我选择记录而不是记录。但理想情况下,业务逻辑是拥有score = 1
的所有记录。现在,记录会做。如果只返回一行并且我的队友可以轻松地同化代码,我只是觉得查询会简单得多。
最终更新:谢谢大家,你们非常善良:)很多答案都很顺利,选择一个真的很令人生畏。我对答案的发现:
始终有效的答案:@GordonLinoff's,@ZaneBiens's,@ZaneBien's another,@Scen's,@JulienCh.'s(最后3个基本相同,但是但我不完全清楚这些是如何工作的:))
仅在第一个条件score = 1
仅返回一行时才有效的答案:@HannoBinder's,@ShlomiNoach's,@DaniellePaquette-Harvey's。目前,我会坚持使用@ Danielle's(这非常简单),如果需要有多行,我会后来还原。
其余的答案,我无法测试,因为它们不是非常具体或与MySQL无关。
@MatthewPK's在上下文中不合适。
奖励赏金并接受答案很难得到如此多的正确答案。我之所以选择this one,因为我觉得它可能更有效率和可读性,但我会接受@ Scen的answer简单明了。
答案 0 :(得分:5)
这看起来很难,因为在这两种情况下你返回的行数可变。
以下查询组合了所有可能的行,然后检查是否存在第一个类型以查看应返回的类型。
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)
注意:返回集包含MatchType。要摆脱这种情况,您需要包含所需列的完整列表。
答案 1 :(得分:4)
此查询将解决您的问题:
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;
与其他答案相反:
No.
mysql
)另请注意,所述查询无法利用ORDER BY
子句上的任何索引,因为我们使用函数包装列。由于FROM clause
条件,OR
不太可能使用索引。
答案 2 :(得分:3)
这是一个更有效的解决方案,应该适合您:
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
中的第一个UNION
返回score
= 1的所有行。第二个SELECT
返回最大行(基于no
= 2 AND ,其中status
= 1的行没有。是否只有一行或多行score
= 2,两者的最大行相同。
这满足您指定的所有条件:
status
= 1 的一行或多行:首先score
返回所有这些行;第二个SELECT
返回空(即使有SELECT
= 2的行。) status
= 1且score
= 2 的行中没有行; 首先status
返回空;第二个SELECT
返回一行(与最大行相同的相同)。 SELECT
= 1且且score
= 2 的行数不止一行时,不存在任何行:首先status
返回空;第二个SELECT
返回SELECT
= 2。 status
= 1或score
= 2 的所有行都不存在:第一行不返回任何内容;第二行也不返回任何内容,呈现空结果。 答案 3 :(得分:2)
完全未经测试,很可能非常低效,但可能有效:
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
)
答案 4 :(得分:1)
假设No.
中仅使用正整数:
select *
from `table`
where status = 2 or score = 1
order by if(score = 1, -2, if(status = 2, -1)), `No.` desc
limit 1;
我做的是创建了一个表达式,行将按行排序。如果得分为1,则表达式将返回-2,仅当status为1时,表达式将返回-1。作为后备,我们按No.
字段按降序排序。
请参阅Shlomi Noach的解决方案,以便在No.
字段具有负值时有效。
答案 5 :(得分:1)
您可以从此查询中获取第一个结果:
-- 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
答案 6 :(得分: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
)
您可以使用索引来提高效率。另外,我不确定条件语句中的查询(检查是否有任何得分为1的行)是否被执行一次或多次。为了安全起见,您可以将其替换为@c并添加以下行:
set @c:=(select max(score) from temp where score=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> */
答案 7 :(得分:1)
我不能(但是?)只在一个查询中看到问题的任何优雅解决方案。
此外,我不确定你的实际问题是什么;您的示例代码似乎很清楚,但我发现很难从
中推断出满足您要求的问题我的查询将有一些WHERE子句,但两者都相同 条件
除此之外,我很惊讶到目前为止还没有人建议使用group by
条款。
这里没有深入探讨MySQL的语法细节,但基本上是
select score, status, MAX(No) as No
from tbl
group by score, status
将为每个“群组”提供恰好单一的记录,其中No
的最大值为。
放入子查询可以改进上述select
,例如
select *
from ( [*] ) as tbl
where
(score = 1)
OR (score != 1 AND status = 2)
OR /* ... more conditions of the above type... */
order by /* ... */
limit 1
([*]
代表上面group
ed select语句
根据需要添加或删除order by score DESC, status DESC
和/或limit 1
子句的变体,您应该非常接近您需要的内容。
答案 8 :(得分:1)
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
答案 9 :(得分:1)
这是我的other solution,但我将这一个作为另一个答案发布,因为它使用了完全不同的技术(WHERE
子句中的条件条件),而不是使用UNION
。< / p>
这避免了必须使用UNION
运算符,这可能是您所追求的(尽管技术上使用两个语句中的UNION
计为“一个”查询)。另一个优点是它与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
你可以使用SQLFiddle Demo来解决这个问题,包括我的答案。
答案 10 :(得分:1)
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
);
我将table
命名为scores
。
SqlFiddle(查询一些假的架构,以便您可以看到结果): http://sqlfiddle.com/#!2/6aac2/1/0
编辑:编辑SQlFiddle以将假模式与问题中的模式匹配。
答案 11 :(得分:0)
SELECT SCORE, STATUS, NO from (
SELECT * , RANK() OVER (PARTITION BY [STATUS] ORDER BY SCORE ASC, NO DESC) AS RANK
FROM `table`
WHERE score = 1 OR [status] = 2 ) x
WHERE X.Rank = 1