WHERE句の代替[クローズ]


16

SELECT使用せずに、列に特定のデータを持つ行のみを作成する方法はありWHEREますか?

たとえば、これがあった場合:

SELECT * FROM Users
WHERE town = 'Townsville'

文にWHERE句を実装する方法はありSELECTますか?

何かのようなもの

SELECT *, town('Townsville') FROM Users

奇妙な質問ですが、仲間から尋ねられた質問です


4
彼らにこれを尋ねている理由を尋ねてください。コンテキストは重要です。
アーロンバートランド

@ AaronBertrand、MikaelEriksson-基本的には仕事中のSQLに関する質問です。「タウンズビルから来たユーザーテーブルから、where句を使用せずにすべてのユーザーを選択してください」という質問に出くわしました。できました!たぶん私はこれに間違った方法でアプローチしているのでしょうか。
ジョシュスティーブンソン

また、このアンケートは、会社での私の雇用状況とはまったく関係ないと述べています。それはほんの少し楽しいです
ジョシュスティーブンソン

回答:


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


非常に素晴らしい!「ユーザー名」などの一意のデータのみを含む列がないシナリオでは、これを使用できないと思いますか?例えば、私が前名、姓、町しか持っていない場合。
ジョシュスティーブンソン

3
@JoshStevenson正しい。ただし、最後の例として重複を保存するために適切に狂った方法を追加し、それから賢明な方法を追加した。
ポールホワイトモニカーを復活

1
以下のためGROUP BYのソリューション、あなたはまた、(クエリが同じ行数を返すようにしてください100%とし)リストでグループ内のPKを追加することができます。もちろんPKがあると仮定します;)
ypercubeᵀᴹ15年


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、次にorder by句で使用される式の最初の行と同じ値を持つすべての行を返します。

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);

別のバージョンtoporder 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

ここには2つの異なるものがあります。

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'

または、インナージョイン。ただし、2番目のテーブルがない場合、これは少し奇妙です。

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

タウンズビル以外のすべての町はヌルになります。問題が解決しました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.