WHERE子句的替代方法


16

有没有办法只SELECT使用一列中具有某些数据的行而不使用WHERE

例如,如果我有这个:

SELECT * FROM Users
WHERE town = 'Townsville'

有没有一种方法可以WHERESELECT语句中实现该子句?

就像是

SELECT *, town('Townsville') FROM Users

这是一个奇怪的问题,但这是我的同龄人问的一个问题


4
问他们为什么要问这个。上下文很重要。
亚伦·伯特兰

@ AaronBertrand,MikaelEriksson-基本上,这是一份有关工作中的SQL的问卷,我遇到一个问题,指出“从Townsville的users表中选择所有用户,而不使用where子句”而且,我不知道有可能!也许我走错了路..?
2015年

还只是说明此调查表与我在公司的受雇状况没有任何关系!只是有点乐趣
Josh Stevenson

Answers:


17

不知道这是否是您想要的那种疯狂的事情。

免责声明:我绝对不知道您为什么要使用它。

SELECT * 
FROM Users AS u
INNER JOIN (SELECT 'Townsville' town) towns 
  ON towns.town = u.Town;

17

数据

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


非常好!我猜想在没有仅包含唯一数据(例如“用户名”)的列的情况下,我将无法使用此功能?例如,如果我只有姓氏,姓氏,城镇。
2015年

3
@JoshStevenson正确,尽管我添加了一种适当的疯狂方式来保存重复项作为最后一个示例,然后是一种明智的方式。
保罗·怀特

1
对于GROUP BY解决方案,您还可以在“分组依据”列表中添加PK(以确保100%确保查询返回的行数与WHERE相同)。当然,假设有一个PK;)
ypercube15


14

您可以将“仅用于娱乐” order bytop(1) with ties

select top(1) with ties *
from dbo.Users
order by case when town = 'Townsville' then 1 else 2 end;

这将使所有行都排在Townsville第一位,因为案例返回1if 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

7

您在这里有两件事。

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'

5

这是使用公用表表达式(CTE)的示例。

with Town as 
(
    select 'Townsville' as Town
)
select *
  from Users u
  join Town  t on u.Town = t.Town

5

好吧,你可以这样做:

    SELECT A.* 
    FROM Users A
         INNER JOIN Users B ON A.Id = B.Id AND B.town = 'Townsville'

严格来说,您没有使用WHERE子句


5

这里有一个 愚蠢的完全合乎逻辑的方式,但我尚未看到。

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

我无法想象为什么这不是要建议的第一件事。:)


-2
SELECT *, 
    case when town='Townsville' then 'Townsville' 
         else null 
    end as Town
FROM Users

除汤斯维尔以外的所有镇都为空。问题解决了。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.