Alternative à la clause WHERE [fermé]

16

Existe-t-il un moyen de n'utiliser que des SELECTlignes contenant certaines données dans une colonne WHERE?

Par exemple, si j'avais ceci:

SELECT * FROM Users
WHERE town = 'Townsville'

existe-t-il un moyen de mettre en œuvre la WHEREclause dans la SELECTdéclaration?

quelque chose comme

SELECT *, town('Townsville') FROM Users

C'est une question bizarre mais c'est celle que mes pairs m'ont posée

Josh Stevenson
la source
4
Demandez-leur pourquoi ils le demandent. Le contexte est important.
Aaron Bertrand
@AaronBertrand, MikaelEriksson - Fondamentalement, c'est un petit questionnaire sur SQL au travail, je suis tombé sur une question indiquant "Sélectionnez tous les utilisateurs de la table des utilisateurs qui viennent de Townsville, sans utiliser une clause where" Et, je ne savais pas que était possible! Peut-être que j'aborde cela de la mauvaise façon ..?
Josh Stevenson
Je précise également que ce questionnaire n'est en aucun cas lié à mon statut d'emploi dans l'entreprise! C'est juste un peu amusant
Josh Stevenson

Réponses:

17

Je ne sais pas si c'est le genre de chose folle que vous recherchiez ....

Avertissement : Je n'ai absolument aucune idée de la raison pour laquelle vous souhaitez utiliser cela.

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

Les données

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

Solutions alternatives

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

Conservation des doublons

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

Production:

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

Pour le dernier exemple:

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

Essayez-le ici: Stack Exchange Data Explorer

Paul White réintègre Monica
la source
Très agréable! Je suppose que je ne serais pas en mesure de l'utiliser dans un scénario où je n'ai pas de colonne contenant uniquement des données uniques telles que «Nom d'utilisateur»? Par exemple, si je n'avais que le prénom, le nom, la ville.
Josh Stevenson
3
@JoshStevenson Correct, bien que j'aie ajouté une manière convenablement folle de conserver les doublons comme exemple final, puis un sensé.
Paul White réintègre Monica
1
Pour les GROUP BYsolutions, vous pouvez également ajouter le PK dans la liste group by (pour être sûr à 100% que les requêtes renvoient le même nombre de lignes que le WHERE). En supposant bien sûr qu'il existe un PK;)
ypercubeᵀᴹ
14

"Juste pour le plaisir", vous pouvez utiliser un order byavectop(1) with ties

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

Cela ordonnera toutes les lignes en Townsvillepremier puisque le cas retourne 1if town = 'Townsville'. Toutes les autres lignes auront un 2retour par le cas.

La with tiesclause oblige la requête à renvoyer toutes les lignes qui sont un "lien" pour la dernière place dans les lignes renvoyées. L'utilisation top(1)en combinaison avec with tiesretournera alors toutes les lignes qui ont la même valeur que la première ligne dans l'expression utilisée dans la clause order by.

Notez, comme Martin Smith l'a souligné dans un commentaire, il retournera toutes les lignes si vous demandez une ville qui n'existe pas dans le tableau.

Si vous ne craignez pas les choses XML des bases de données, vous pouvez utiliser un prédicat dans la fonction nodes ().

Emprunter l'installation de 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);

Une autre version avec topet order byqui fonctionne réellement lors de la recherche de villes non existantes.

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
la source
7

Vous avez deux choses différentes ici.

SELECT * FROM Users
WHERE town = 'Townsville'

Limitera le nombre de lignes que vous récupérez à celles où town =Townsville

SELECT *, town('Townsville') FROM Users

Va passer le littéral Townsvilleà une fonction appelée town. Cela ne restreindra pas les lignes renvoyées par la requête et, en fait, si la fonction renvoie autre chose qu'une seule valeur, vous obtiendrez une erreur.

Il existe d'autres façons de limiter le nombre de lignes que vous récupérez d'une requête. La clause HAVING par exemple. Mais il a plusieurs autres exigences.

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

Ou un INNER JOIN bien que celui-ci soit un peu bizarre si vous n'avez pas de deuxième table.

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

Voici un exemple utilisant une expression de table commune (CTE).

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

Eh bien, vous pouvez le faire:

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

À strictement parler, vous n'utilisez pas la clause WHERE

druzin
la source
5

Voici une façon idiote tout à fait logique de le faire que je ne vois pas encore ....

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

Je ne peux pas imaginer pourquoi ce n'était pas la première chose à suggérer. :)

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

Toutes les villes, à l'exception de Townsville, seraient nulles. Problème résolu.

ColorfulWind
la source