Intérieure Joindre une Table à elle-Même
J'ai une table qui utilise les deux en identifiant les colonnes, appelons-id et nom d'utilisateur. ID est unique dans chaque enregistrement, et identifiant est unique pour l'utilisateur mais il est dans de nombreux dossiers.
Ce dont j'ai besoin pour faire est d'obtenir un enregistrement de l'Utilisateur par le nom d'utilisateur et ensuite rejoindre ce record pour le premier enregistrement que nous avons pour l'utilisateur. La logique de la requête est comme suit:
SELECT v1.id, MIN(v2.id) AS entryid, v1.userid
FROM views v1
INNER JOIN views v2
ON v1.userid = v2.userid
Je suis en espérant que je n'ai pas à rejoindre la table à une sous-requête qui gère le min() le morceau de code qui semble être assez lente.
Avez-vous un index sur le nom de la colonne?
Ou un composé de l'indice sur l'id utilisateur et Id? Est l'Id de la PK pour la ligne?
Parce que vous devriez faire une sous-requête et il ne devrait pas être lent. Si vous pouvez modifier les structures de données, vous pouvez toujours ajouter une colonne pour le premier enregistrement d'un utilisateur et de la maintenir dans le code, ou de les maintenir à une table différente, si cela va être trop lent...
ID est un PK actuellement et j'ai indices d'installation à travers le nom d'utilisateur et de colonnes. La table de base de données est actuellement à ~5 000 000 de lignes.
Est que votre requête? Je pense que je suis absent pourquoi vous avez besoin d'une jointure.
Ou un composé de l'indice sur l'id utilisateur et Id? Est l'Id de la PK pour la ligne?
Parce que vous devriez faire une sous-requête et il ne devrait pas être lent. Si vous pouvez modifier les structures de données, vous pouvez toujours ajouter une colonne pour le premier enregistrement d'un utilisateur et de la maintenir dans le code, ou de les maintenir à une table différente, si cela va être trop lent...
ID est un PK actuellement et j'ai indices d'installation à travers le nom d'utilisateur et de colonnes. La table de base de données est actuellement à ~5 000 000 de lignes.
Est que votre requête? Je pense que je suis absent pourquoi vous avez besoin d'une jointure.
OriginalL'auteur Dave Long | 2012-12-03
Vous devez vous connecter pour publier un commentaire.
Je pense (ce n'est pas tout à fait clair que vous voulez trouver pour chaque utilisateur, les lignes de la table qui ont un minimum de
id
, donc une ligne par utilisateur.Dans ce cas, vous une utiliser une sous-requête (une table dérivée) et le joindre à la table:
Ci-dessus peut également être écrit à l'aide d'un Expression de Table commune (CTE), si vous les aimez:
Pourrait être très efficace avec un index sur
(userid, id)
.Avec SQL-Server, vous pouvez écrire cela à l'aide de la
ROW_NUMBER()
fonction de fenêtre:Vérifiez également la dernière requête (j'ai eu une erreur, c'est corrigé maintenant). Les fonctions de la fenêtre sont très utiles.
OriginalL'auteur ypercubeᵀᴹ
Bien, pour utiliser le
MIN
de la fonction ainsi que de non-agrégation des colonnes, vous avez le groupe de l'instruction. C'est possible avec la requête que vous avez... (EDIT fondée sur d'autres info)... toutefois, si ce est juste un exemple simple et vous êtes à la recherche de tirer plus de données avec cette requête, il devient rapidement impossible de solution.
Ce que vous semblez vouloir, c'est une liste de toutes les données utilisateur de ce point de vue, avec un lien sur chaque ligne, ce qui nous ramène à la "première" record qui existe pour le même utilisateur. La requête ci-dessus, vous obtiendrez ce que vous voulez, mais il y a beaucoup plus de facilité pour déterminer le premier enregistrement de chaque utilisateur:
Le premier enregistrement pour chaque nom d'utilisateur est votre "point d'entrée". Je crois que je comprends pourquoi vous voulez le faire de la façon que vous avez spécifié, et la première requête que j'ai donné sera raisonnablement performant, mais vous aurez à prendre en compte si de ne pas avoir à utiliser la clause order by pour obtenir la réponse correcte vaut la peine.
Je veux en fait une multitude de lignes dans le résultat de l'objet, mais cela me donne ce que je veux dans le résultat. Un exemple que cela ne semble pas fonctionner, est ce que lorsque la requête est pour la "saisie" sens où v1.id et v2.id sont les mêmes. Maintenant que la requête n'aura pas d'enregistrement dans le résultat. Je suppose que je peux faire une jointure droite et est min(v2.id) est nulle utiliser la v1.id dans les deux colonnes?
Je crois que je comprends maintenant; il veut une requête qui va lui donner toutes les lignes associées à un utilisateur, et il veut connaître l'ID de la première de ces enregistrement de l'utilisateur, qui est d'une importance particulière. Personnellement, je pense que ce serait mieux servi avec un
ORDER BY v1.id
clause (le premier résultat est votre "entrée"), mais si il l'artisanat un objet de mappage de déclaration avec une backreference cela peut simplifier les choses.Je n'ai pas très bien compris ce que tu voulais. Je pense que je fais maintenant. J'ai édité l'instruction et la plus complète édition suivra.
OriginalL'auteur KeithS
edit-1: comme l'a souligné dans les commentaires, cette solution utilise une sous-requête. Cependant, il n'utilise pas les fonctions d'agrégation, qui (selon la base de données) peut avoir un impact énorme sur les performances.
Peut atteindre sans sous-requête (voir ci-dessous).
De toute évidence, un index sur
views.userid
est d'extraordinaires de la valeur pour la performance.... Vous êtes en utilisant une sous-requête.
Assez juste, les gars. Il utilise une sous-requête, mais pas celui qui utilise des agrégats (je ne vais pas corriger le texte en sorte que vos commentaires séjour en cours de validité). Cependant, cette solution évolue beaucoup mieux par rapport à joint sur
MAX/MIN
, parce que les indices peuvent être utilisés.Je n'ai pas downvoted, parce que c'est une réécriture de la requête. L'efficacité doit être vérifiée et, bien sûr, peut varier en fonction du SGBD et les données de taille et de la répartition.
OriginalL'auteur van