J'ai une table très étroite: user_id, ascestry.
La colonne user_id est explicite.
La colonne d'ascendance contient le pays d'origine des ancêtres de l'utilisateur.
Un utilisateur peut avoir plusieurs lignes dans la table, car il peut avoir des ancêtres de plusieurs pays.
Ma question est la suivante: comment sélectionner des utilisateurs dont les ancêtres sont originaires de plusieurs pays spécifiés?
Par exemple, montrez-moi tous les utilisateurs qui ont des ancêtres d'Angleterre, de France et d'Allemagne et renvoyez une ligne par utilisateur répondant à ce critère.
Quel est ce SQL?
user_id ancestry
--------- ----------
1 England
1 Ireland
2 France
3 Germany
3 Poland
4 England
4 France
4 Germany
5 France
5 Germany
Dans le cas des données ci-dessus, je m'attendrais à un résultat de "4", car user_id 4 a des ancêtres d'Angleterre, de France et d'Allemagne.
Merci d'avance.
P.S. Pour clarifier: oui, les colonnes user_id/ascestry constituent une paire unique, de sorte qu'un pays ne soit pas répété pour un utilisateur donné.
P.P.S. Je recherche des utilisateurs provenant des 3 pays - Angleterre, France et Allemagne (et les pays sont arbitraires).
P.P.P.S. Je ne cherche pas de réponses spécifiques à un certain SGBDR. Je cherche à répondre à ce problème "en général".
Je suis content de régénérer la clause where pour chaque requête fournie, ce qui permet de générer la clause where par programmation (par exemple, je peux créer une fonction pour construire la clause WHERE/FROM - WHERE).
Essaye ça:
Select user_id
from yourtable
where ancestry in ('England', 'France', 'Germany')
group by user_id
having count(user_id) = 3
La dernière ligne signifie que l'ascendance de l'utilisateur comprend les 3 pays.
SELECT DISTINCT (user_id)
FROM [user]
WHERE user.user_id In (select user_id from user where ancestry = 'England')
And user.user_id In (select user_id from user where ancestry = 'France')
And user.user_id In (select user_id from user where ancestry = 'Germany');`
Les utilisateurs qui ont un des les 3 pays
SELECT DISTINCT user_id
FROM table
WHERE ancestry IN('England','France','Germany')
Les utilisateurs qui ont all 3 countries
SELECT DISTINCT A.userID
FROM table A
INNER JOIN table B on A.user_id = B.user_id
INNER JOIN table C on A.user_id = C.user_id
WHERE A.ancestry = 'England'
AND B.ancestry = 'Germany'
AND C.ancestry = 'France'
force brute (et seulement testé sur un système Oracle, mais je pense que c'est assez standard):
select distinct usr_id from users where user_id in (
select user_id from (
Select user_id, Count(User_Id) As Cc
From users
GROUP BY user_id
) Where Cc =3
)
and ancestry in ('England', 'France', 'Germany')
;
edit: J'aime mieux la réponse de @ HuckIt.
attirer des gens de plusieurs pays:
SELECT u1.user_id
FROM users u1
JOIN users u2
on u1.user_id = u2.user_id
AND u1.ancestry <> u2.ancestry
Obtenez des personnes de 2 pays spécifiques:
SELECT u1.user_id
FROM users u1
JOIN users u2
on u1.user_id = u2.user_id
WHERE u1.ancestry = 'Germany'
AND u2.ancestry = 'France'
Pour 3 pays ... rejoignez trois fois. Pour obtenir le résultat (s) une seule fois, distincte.
Cela aura pour utilisateurs qui ont 3 lignes (ayant ... compte) et ensuite vous spécifiez quelles lignes sont autorisées. Notez que si vous n'avez pas de clé unique sur (user_id, ancestry)
, un utilisateur avec "id, england" qui apparaît 3 fois correspondra également ... donc cela dépend de votre structure de table et/ou de vos données.
SELECT user_id
FROM users u1
WHERE ancestry = 'Germany'
OR ancestry = 'France'
OR ancestry = 'England'
GROUP BY user_id
HAVING count(DISTINCT ancestry) = 3
comme la réponse ci-dessus, mais j'ai un enregistrement en double, donc je dois créer une sous-requête avec distinct
Select user_id
(
select distinct userid
from yourtable
where user_id = @userid
) t1
where
ancestry in ('England', 'France', 'Germany')
group by user_id
having count(user_id) = 3
c’est ce que j’ai utilisé car j’ai plusieurs enregistrements (journaux de téléchargement) et cela vérifie que tous les fichiers requis ont été téléchargés.
l’une des méthodes permettant d’obtenir tous les identificateurs d’utilisateur correspondant à toutes les conditions est la suivante:
SELECT DISTINCT user_id FROM table WHERE ancestry IN ('England', '...', '...') GROUP BY user_id HAVING count(*) = <number of conditions that has to be satisfied>
etc. Si vous devez prendre tous les user_ids qui remplissent au moins une condition, alors vous pouvez le faire.
SELECT DISTINCT user_id from table where ancestry IN ('England', 'France', ... , '...')
Je ne sais pas s'il existe quelque chose de similaire à IN mais qui joint les conditions avec AND au lieu de OR
Cette question date de quelques années, mais je suis arrivée via un duplicata. Je veux aussi suggérer une solution plus générale. Si vous savez que vous avez toujours un nombre fixe d'ancêtres, vous pouvez utiliser certaines auto-jointes comme déjà suggéré dans les réponses. Si vous voulez une approche générique, continuez à lire.
Ce dont vous avez besoin ici s’appelle Quotient en algèbre relationnelle. Le quotient est plus ou moins l'inversion du produit cartésien (ou jointure croisée en SQL).
Disons que votre ancêtre A
est (j'utilise une notation de table ici, je pense que c'est mieux pour comprendre)
ancestry
-----------
'England'
'France'
'Germany'
et votre ensemble utilisateur U
est
user_id
--------
1
2
3
Le produit cartésien C=AxU
est alors:
user_id | ancestry
---------+-----------
1 | 'England'
1 | 'France'
1 | 'Germany'
2 | 'England'
2 | 'France'
2 | 'Germany'
3 | 'England'
3 | 'France'
3 | 'Germany'
Si vous calculez le quotient défini U=C/A
, alors vous obtenez
user_id
--------
1
2
3
Si vous refaites le produit cartésien UXA
, vous aurez à nouveau C
. Mais notez que pour un ensemble T
, (T/A)xA
ne reproduira pas nécessairement T
. Par exemple, si T
est
user_id | ancestry
---------+-----------
1 | 'England'
1 | 'France'
1 | 'Germany'
2 | 'England'
2 | 'France'
alors (T/A)
est
user_id
--------
1
(T/A)xA
sera alors
user_id | ancestry
---------+------------
1 | 'England'
1 | 'France'
1 | 'Germany'
Notez que les enregistrements pour user_id=2
ont été éliminés par les opérations Quotient et Produit cartésien.
Votre question est la suivante: quel user_id a des ancêtres de tous les pays de votre groupe d'ancêtres? En d'autres termes, vous voulez U=T/A
où T
est votre ensemble d'origine (ou votre table).
Pour implémenter le quotient en SQL, vous devez suivre 4 étapes:
Alors faisons-le étape par étape. J'utiliserai la syntaxe TSQL (serveur Microsoft SQL), mais il devrait être facilement adaptable à d'autres SGBD. En tant que nom pour la table (user_id, ancestry)
je choisis ancestor
CREATE TABLE ancestry_set (ancestry nvarchar(25))
INSERT INTO ancestry_set (ancestry) VALUES ('England')
INSERT INTO ancestry_set (ancestry) VALUES ('France')
INSERT INTO ancestry_set (ancestry) VALUES ('Germany')
CREATE TABLE ancestor ([user_id] int, ancestry nvarchar(25))
INSERT INTO ancestor ([user_id],ancestry) VALUES (1,'England')
INSERT INTO ancestor ([user_id],ancestry) VALUES(1,'Ireland')
INSERT INTO ancestor ([user_id],ancestry) VALUES(2,'France')
INSERT INTO ancestor ([user_id],ancestry) VALUES(3,'Germany')
INSERT INTO ancestor ([user_id],ancestry) VALUES(3,'Poland')
INSERT INTO ancestor ([user_id],ancestry) VALUES(4,'England')
INSERT INTO ancestor ([user_id],ancestry) VALUES(4,'France')
INSERT INTO ancestor ([user_id],ancestry) VALUES(4,'Germany')
INSERT INTO ancestor ([user_id],ancestry) VALUES(5,'France')
INSERT INTO ancestor ([user_id],ancestry) VALUES(5,'Germany')
1) Créez le produit cartésien de votre ensemble d'ascendance et l'ensemble de tous les user_ids.
SELECT a.[user_id],s.ancestry
FROM ancestor a, ancestry_set s
GROUP BY a.[user_id],s.ancestry
2) Trouver tous les enregistrements du produit cartésien qui n’ont pas de partenaire dans le jeu d’origine (jointure à gauche) et
3) Extrayez les user_ids du résultat de 2)
SELECT DISTINCT cp.[user_id]
FROM (SELECT a.[user_id],s.ancestry
FROM ancestor a, ancestry_set s
GROUP BY a.[user_id],s.ancestry) cp
LEFT JOIN ancestor a ON cp.[user_id]=a.[user_id] AND cp.ancestry=a.ancestry
WHERE a.[user_id] is null
4) Renvoie tous les user_ids de l'ensemble d'origine qui ne sont pas inclus dans l'ensemble de résultats de 3)
SELECT DISTINCT [user_id]
FROM ancestor
WHERE [user_id] NOT IN (
SELECT DISTINCT cp.[user_id]
FROM (SELECT a.[user_id],s.ancestry
FROM ancestor a, ancestry_set s
GROUP BY a.[user_id],s.ancestry) cp
LEFT JOIN ancestor a ON cp.[user_id]=a.[user_id] AND cp.ancestry=a.ancestry
WHERE a.[user_id] is null
)