有没有办法只SELECT
使用一列中具有某些数据的行而不使用WHERE
?
例如,如果我有这个:
SELECT * FROM Users
WHERE town = 'Townsville'
有没有一种方法可以WHERE
在SELECT
语句中实现该子句?
就像是
SELECT *, town('Townsville') FROM Users
这是一个奇怪的问题,但这是我的同龄人问的一个问题
有没有办法只SELECT
使用一列中具有某些数据的行而不使用WHERE
?
例如,如果我有这个:
SELECT * FROM Users
WHERE town = 'Townsville'
有没有一种方法可以WHERE
在SELECT
语句中实现该子句?
就像是
SELECT *, town('Townsville') FROM Users
这是一个奇怪的问题,但这是我的同龄人问的一个问题
Answers:
DECLARE @Example AS table
(
UserName varchar(30) NULL,
Town varchar(30) NULL
);
INSERT @Example
(UserName, Town)
VALUES
('Aaron', 'Not Townsville'),
('Bob', 'Not Townsville'),
('Charles', 'Townsville'),
('Charles', 'Townsville'),
('Charles', 'Townsville'),
('Charles', 'Townsville'),
('Dan', 'Townsville'),
('Eric', 'Not Townsville');
SELECT E.UserName, E.Town
FROM @Example AS E
GROUP BY E.Town, E.UserName
HAVING E.Town = 'Townsville'
-- OR
SELECT E.UserName, 'Townsville' AS Town
FROM @Example AS E
GROUP BY E.UserName
HAVING 1 = MAX(CASE WHEN E.Town = 'Townsville' THEN 1 ELSE 0 END);
-- OR
SELECT E.UserName, E.Town
FROM @Example AS E
INTERSECT
SELECT E.UserName, 'Townsville' AS Town
FROM @Example AS E
-- :)
SELECT E.UserName, E.Town
FROM @Example AS E
CROSS APPLY (VALUES(NEWID())) AS CA (n)
GROUP BY E.Town, E.UserName, CA.n
HAVING E.Town = 'Townsville'
-- Simulating INTERSECT ALL
SELECT
R.UserName,
R.Town
FROM
(
SELECT
E.UserName,
E.Town,
rn =
ROW_NUMBER() OVER (
PARTITION BY E.UserName, E.Town
ORDER BY E.UserName, E.Town)
FROM @Example AS E
INTERSECT
SELECT
E.UserName,
'Townsville',
rn =
ROW_NUMBER() OVER (
PARTITION BY E.UserName
ORDER BY E.UserName)
FROM @Example AS E
) AS R;
输出:
╔══════════╦════════════╗
║ UserName ║ Town ║
╠══════════╬════════════╣
║ Charles ║ Townsville ║
║ Dan ║ Townsville ║
╚══════════╩════════════╝
对于最后一个示例:
╔══════════╦════════════╗
║ UserName ║ Town ║
╠══════════╬════════════╣
║ Charles ║ Townsville ║
║ Charles ║ Townsville ║
║ Charles ║ Townsville ║
║ Charles ║ Townsville ║
║ Dan ║ Townsville ║
╚══════════╩════════════╝
在这里尝试: Stack Exchange Data Explorer
GROUP BY
解决方案,您还可以在“分组依据”列表中添加PK(以确保100%确保查询返回的行数与WHERE相同)。当然,假设有一个PK;)
另一种方式。
SELECT U.*
FROM dbo.Users U
CROSS APPLY (SELECT Town INTERSECT SELECT 'Townsville' ) CA;
您可以将“仅用于娱乐” order by
与top(1) with ties
select top(1) with ties *
from dbo.Users
order by case when town = 'Townsville' then 1 else 2 end;
这将使所有行都排在Townsville
第一位,因为案例返回1
if town = 'Townsville'
。所有其他行将由2
该案例返回。
的 with ties
子句使查询返回所有与返回的行中的最后一个地方“绑”在一起的行。使用top(1)
结合with ties
然后将返回具有相同的值作为表达式中的第一行由子句中的顺序使用的所有行。
请注意,正如Martin Smith在评论中指出的那样,它将返回 如果您要查询表中不存在的城镇,所有行。
如果您不担心数据库的XML问题,则可以在nodes()函数中使用谓词。
从Paul White借用安装程序。
select T.X.value('(UserName/text())[1]', 'varchar(30)') as UserName,
T.X.value('(Town/text())[1]', 'varchar(30)') as Town
from (
select *
from @Example
for xml path('row'), type
) as C(X)
cross apply C.X.nodes('/row[Town = "Townsville"]') as T(X);
当搜索不存在的城镇时,具有top
和的另一个版本order by
实际上起作用。
select top(
select sum(case when town = 'Townsville' then 1 end)
from @Example
) *
from @Example
order by case when town = 'Townsville' then 1 else 2 end
您在这里有两件事。
SELECT * FROM Users
WHERE town = 'Townsville'
将限制您返回的行数仅限于Town =Townsville
SELECT *, town('Townsville') FROM Users
将文字传递Townsville
给一个名为town
。它不会限制查询返回的行,并且实际上,如果该函数返回除单个值以外的任何值,您将得到一个错误。
还有其他方法可以限制您从查询中获得的行数。例如,HAVING子句。但是它还有其他一些要求。
SELECT town FROM Users
GROUP BY town
HAVING town = 'Townsville'
或INNER JOIN,尽管如果您没有第二张桌子,这有点奇怪。
SELECT * FROM Users
INNER JOIN (SELECT 1 col1) UselessTable
ON Users.town = 'Townsville'
这里有一个 愚蠢的完全合乎逻辑的方式,但我尚未看到。
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; -- Our important work should be all the database cares about
GO
BEGIN TRANSACTION
DECLARE @MyTableVar table(<all columns in order from the user table>, oldtown VARCHAR(50));
UPDATE users
SET town = N'Townsville'
OUTPUT
inserted.* -- We don't want to have to type out the columns because that would be too much work
deleted.town
INTO @MyTableVar;
--Display the result set of the table variable to prevent undesirables from sullying our output by inserting incorrect data even though we should have exclusive access.
SELECT * -- Select everything we want except for the 'oldtown' column because that data was probably wrong anyway
FROM @MyTableVar;
UPDATE u -- We don't want to be bad stewards of our data
SET
town = oldtown
FROM users u
INNER JOIN @MyTableVar mtv ON mtv.town = u.town, <Match up all the columns to REALLY ensure we are matching the proper row>
COMMIT TRANSACTION -- Make sure we save our work
我无法想象为什么这不是要建议的第一件事。:)