Alternative zur WHERE-Klausel [geschlossen]

16

Gibt es eine Möglichkeit, nur SELECTZeilen mit bestimmten Daten in einer Spalte zu verwenden, ohne WHERE?

zB wenn ich das hätte:

SELECT * FROM Users
WHERE town = 'Townsville'

Gibt es eine Möglichkeit, die WHEREKlausel in die SELECTAnweisung zu implementieren ?

etwas wie

SELECT *, town('Townsville') FROM Users

Es ist eine bizarre Frage, aber sie wurde mir von Gleichaltrigen gestellt

Josh Stevenson
quelle
4
Fragen Sie sie, warum sie das fragen. Der Kontext ist wichtig.
Aaron Bertrand
@AaronBertrand, MikaelEriksson - Im Grunde genommen handelt es sich um einen kleinen Fragebogen zu SQL bei der Arbeit. Dabei stellte sich die Frage: "Wählen Sie alle Benutzer aus der Benutzertabelle aus, die aus Townsville stammen, ohne eine where-Klausel zu verwenden." Und das wusste ich nicht war möglich! Vielleicht gehe ich das falsch an ..?
Josh Stevenson
Ich möchte nur darauf hinweisen, dass dieser Fragebogen in keiner Weise mit meinem Beschäftigungsstatus im Unternehmen zusammenhängt! Es ist nur ein bisschen Spaß
Josh Stevenson

Antworten:

17

Ich bin mir nicht sicher, ob das die verrückte Sache ist, nach der du gesucht hast ...

Haftungsausschluss : Ich habe absolut keine Ahnung, warum Sie dies verwenden möchten.

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

Daten

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

Alternativlösungen

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

Duplikate behalten

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

Ausgabe:

╔══════════╦════════════╗
 UserName     Town    
╠══════════╬════════════╣
 Charles   Townsville 
 Dan       Townsville 
╚══════════╩════════════╝

Für das letzte Beispiel:

╔══════════╦════════════╗
 UserName     Town    
╠══════════╬════════════╣
 Charles   Townsville 
 Charles   Townsville 
 Charles   Townsville 
 Charles   Townsville 
 Dan       Townsville 
╚══════════╩════════════╝

Probieren Sie es hier aus: Stack Exchange Data Explorer

Paul White sagt GoFundMonica
quelle
Sehr schön! Ich vermute, ich könnte dies nicht in einem Szenario verwenden, in dem ich keine Spalte habe, die nur eindeutige Daten wie "Benutzername" enthält. ZB wenn ich nur Vorname, Nachname, Ort hätte.
Josh Stevenson
3
@JoshStevenson Richtig, obwohl ich als letztes Beispiel einen angemessen verrückten Weg hinzugefügt habe, um Duplikate zu erhalten, und dann einen vernünftigen.
Paul White sagt GoFundMonica
1
Für die GROUP BYLösungen können Sie auch die PK in die Liste der Gruppen nach hinzufügen (um 100% sicher zu sein, dass die Abfragen die gleiche Anzahl von Zeilen wie WHERE zurückgeben). Vorausgesetzt natürlich, es gibt eine PK;)
ypercubeᵀᴹ
14

"Nur zum Spaß" können Sie order bymit verwendentop(1) with ties

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

Dies ordnet alle Zeilen mit Townsvillezuerst an, da der Fall 1if zurückgibt town = 'Townsville'. Alle anderen Zeilen werden 2von der Groß- / Kleinschreibung zurückgegeben.

Die with tiesKlausel bewirkt, dass die Abfrage alle Zeilen zurückgibt, die für den letzten Platz in den zurückgegebenen Zeilen "gleich" sind. Die Verwendung top(1)in Kombination mit with tiesdann alle Zeilen zurückgeben , die den gleichen Wert wie die erste Zeile in Ausdruck in der ORDER BY - Klausel verwendet wird, hat.

Beachten Sie, wie Martin Smith in einem Kommentar betont hat, dass alle Zeilen zurückgegeben werden, wenn Sie nach einer Stadt fragen, die in der Tabelle nicht vorhanden ist.

Wenn Sie keine Angst vor den XML-Dingen von Datenbanken haben, können Sie ein Prädikat in der node () -Funktion verwenden.

Das Setup von Paul White ausleihen.

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

Eine andere Version mit topund order bydas funktioniert eigentlich bei der Suche nach nicht existierenden Städten.

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
Mikael Eriksson
quelle
7

Sie haben hier zwei verschiedene Dinge.

SELECT * FROM Users
WHERE town = 'Townsville'

Beschränkt die Anzahl der Zeilen, die Sie zurückerhalten, auf die Zeilen, in denen town = istTownsville

SELECT *, town('Townsville') FROM Users

Wird das Literal Townsvillean eine aufgerufene Funktion übergeben town. Die von der Abfrage zurückgegebenen Zeilen werden nicht eingeschränkt. Wenn die Funktion nur einen einzigen Wert zurückgibt, wird ein Fehler angezeigt.

Es gibt andere Möglichkeiten, die Anzahl der Zeilen zu beschränken, die Sie von einer Abfrage zurückerhalten. Die HAVING-Klausel zum Beispiel. Es gibt aber noch einige andere Anforderungen.

SELECT town FROM Users
GROUP BY town
HAVING town = 'Townsville'

Oder einen INNER JOIN, obwohl dieser etwas seltsam ist, wenn Sie keinen zweiten Tisch haben.

SELECT * FROM Users
INNER JOIN (SELECT 1 col1) UselessTable
    ON Users.town = 'Townsville'
Kenneth Fisher
quelle
5

Hier ist ein Beispiel mit einem allgemeinen Tabellenausdruck (CTE).

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

Nun, du könntest das tun:

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

Genau genommen verwenden Sie die WHERE-Klausel nicht

Druzin
quelle
5

Hier ist ein idiotischer, ganz logischer Weg, den ich noch nicht sehe ...

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

Ich kann mir nicht vorstellen, warum dies nicht als erstes vorgeschlagen wurde. :)

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

Alle Städte außer Townsville wären null. Problem gelöst.

ColorfulWind
quelle