2010-12-13 21 views
4

J'ai une table appelée TempAllAddresses avec les colonnes suivantes - ID, Address, State. Je veux remplir une nouvelle table avec Address, State et Count. Count doit représenter le nombre d'enregistrements présents dans la table TempAllAddresses qui ont une adresse comme cette adresse suivie d'un caractère générique. Si ce fait n'a pas de sens, voici un exemple pour illustrer - Disons que j'ai un dossier comme celui-ci:Quel est le problème avec cette jointure d'une table à elle-même?

ID  Address  State 
12345 13 Phoenix NY 

Ce que je veux faire est d'insérer un nouvel enregistrement dans une nouvelle table appelée AddressCount qui a 13 Phoenix le Address, NY pour le State, et le nombre d'enregistrements dans la table qui ont NY comme état et une adresse COMME '13 Phoenix% 'pour le Count.

Je veux accomplir cela avec une jointure interne de TempAllAddresses sur lui-même. Voilà ce que je l'ai essayé, mais il ne semble pas accomplir ce que je cherche:

SELECT t1.Address, t1.State, COUNT(t2.address) As NumEntities 
FROM TempAllAddresses t1 
INNER JOIN TempAllAddresses t2 
ON t1.state = t2.state 
AND T2.Address LIKE t1.address + '%' 
GROUP BY t1.State, t1.Address 

Le comte est définitivement hors, bien que. Cela devrait être équivalent à "SELECT COUNT(*) FROM TempAllAddresses WHERE State=thisRecordsState and Address LIKE thisRecordsAddress + '%'". Comment puis-je accomplir cela? Qu'est-ce que je fais mal?

Edit:

Le comte semble être hors de la manière suivante - Si j'ai un disque comme je l'ai mentionné plus haut, puis-je avoir 2 autres enregistrements qui ont aussi un état de New York, et , il me semble

13 Phoenix NY 3 

au lieu de cela à obtenir:: alors avoir des adresses de « 13 Phoenix route » et « 13 Phoenix Rd », alors je veux entrer dans ma table finale un dossier comme celui-ci

13 Phoenix NY 9 

Je ne sais pas très bien ce qui se passe ici ... une sorte de produit cartésien? Permutations ...? Quelqu'un peut-il expliquer cela?

Edit 2: Une autre édition que je semble être mal compris (et vraiment besoin d'une solution :() ... Voici une requête avec une sous-sélection corrélative qui accomplit ce que je cherche je. souhaitez faire la même chose avec une jointure de la table sur elle-même plutôt que d'une sous-sélection.

SELECT Address, State, 
    (SELECT Count(*) 
    FROM TempAllAddresses innerQry 
    WHERE innerQry.address LIKE outerQry.address + '%' 
     AND innerQry.state = outerQry.state) As NumEntities 
FROM TempAllAddresses outerQry 

en fait, pour chaque enregistrement, je veux obtenir le nombre d'enregistrements dans la table qui ont le même état et une adresse qui commence par cette adresse (ou est égale à ... Je veux inclure cette adresse dans le compte)

+0

Comment le compte est-il désactivé? Est-ce que chaque ligne devrait se compter (tout compte> = 1)? –

+0

il semble réellement correct. si vous ne résumez pas (c'est-à-dire groupe), quel est le résultat attendu (pour t2.address)? – lijie

+0

désolé, je suis un peu flou à ce sujet, donc je ne suis pas sûr si je comprends complètement vos commentaires ... Je vais essayer de mettre à jour la question pour expliquer comment le compte est désactivé – froadie

Répondre

0

Essayez ceci:

SELECT Orig_Address, State, COUNT(Similar_Address) 
From 
(
    SELECT t1.Address Orig_Address, 
     t1.State State, 
     t2.address Similar_Address 
    FROM TempAllAddresses t1 
    INNER JOIN TempAllAddresses t2 
     ON t1.state = t2.state 
    AND T2.Address LIKE t1.address + '%' 
    AND t1.address <> t2.address 
) 
GROUP BY State, Orig_Address 

EDIT: oublié d'inclure la différence entre t1.address et t2.address, comme @Spiny Norman dit, puisque vous ne voulez probablement pas de comparer une adresse à lui-même.

HTH

+0

et en quoi est-ce différent du regroupement par t1.address en premier lieu ?? – lijie

+0

Cela me donne exactement les mêmes résultats, et le compte est toujours éteint ... – froadie

+0

@lijie, désolé, vous avez raison. J'ai écrit cela en premier lieu, puis réalisé que c'était faux et je voulais juste mettre ma proposition de sélection, mais j'ai oublié de supprimer cette partie du texte. Je vais l'éditer en conséquence. –

0

EDIT: [snip vieilleries]

Essayez ceci:

SELECT t1.Address, t1.State, COUNT(distinct t2.id) As NumEntities 
FROM TempAllAddresses t1 
INNER JOIN TempAllAddresses t2 
ON t1.state = t2.state 
AND T2.Address LIKE t1.address + '%' 
GROUP BY t1.State, t1.Address 
+0

En essayant votre première suggestion, je reçois 0 pour NumEntities pour toutes les lignes ... Je suppose que c'est parce que t1.Address <> t1.Address est toujours faux. Y a-t-il une faute de frappe quelque part? – froadie

+0

Yep :) Je veux dire t1.Address <> t2.address. Édité. (en passant, je pense que la solution '_%' est plus élégante, si votre serveur de base de données le supporte). –

+0

Cela ne semble pas me donner les résultats corrects du tout ... Je vérifie des résultats aléatoires et ils sont totalement désactivés, mais pas dans un modèle perceptible. Peut-être que cela a quelque chose à voir avec la gauche? Je ne suis pas tout à fait sûr pourquoi vous pensez que c'est une solution au problème, donc je ne peux pas vraiment comprendre comment le modifier ... – froadie

0

QUERY A:

SELECT t1.Address, t1.State, COUNT(t2.address) As NumEntities 
FROM TempAllAddresses t1 
INNER JOIN TempAllAddresses t2 
ON t1.state = t2.state 
AND T2.Address LIKE t1.address + '%' 
GROUP BY t1.State, t1.Address 

n'est pas équivalent à

QUERY B :

SELECT Address, State, 
    (SELECT Count(*) 
    FROM TempAllAddresses innerQry 
    WHERE innerQry.address LIKE outerQry.address + '%' 
     AND innerQry.state = outerQry.state) As NumEntities 
FROM TempAllAddresses outerQry 

parce que B produit une ligne pour chaque ligne de la table d'origine (TempAllAddresses), tandis qu'un groupe de volonté ensemble de lignes dans la table d'origine qui ont le même état et l'adresse. Pour résoudre cela, GROUP BY t1.ID, t1.State, t1.Address à la place.

+0

@lijie a accepté, mais je ne pense pas que la version sous-sélective fasse vraiment ce que froadie veut malgré ce qu'il dit - je pense qu'il est plus probable qu'il veut 1 ligne pour chaque adresse distincte, état –

+0

@jackpdouglas: oui je pense que c'est l'intention réelle (mais cela continue à faire réfléchir jusqu'à ce que l'OP confirme). à cet effet, ajouterait simplement 'DISTINCT' après le mot-clé' SELECT' (je n'ai pas assez d'expérience pour le savoir, mais c'est ce que j'essayerais naturellement si je ne voulais pas de sous-requêtes). – lijie

+0

@lijie qui obtiendrait le «bon» nombre de lignes, mais le 'count' ne fonctionnerait pas - voir ma réponse pour ce que je ferais à la place –

0

Il existe un double comptage lorsque plusieurs lignes ont exactement la même adresse.

Essayez:

SELECT t1.Address, t1.State, COUNT(t2.address) As NumEntities 
FROM (select distinct Address, State from TempAllAddresses) t1 
INNER JOIN TempAllAddresses t2 
ON t1.state = t2.state 
AND T2.Address LIKE t1.address + '%' 
GROUP BY t1.State, t1.Address 
0

Nested GroupBy:

  • Le sous-requête trouvera l'adresse la plus courte pour chaque adresse distincte.
  • Ceci ne tient pas compte de la sensibilité à la casse.
  • Ensuite, chaque version de ces adresses est comptée.

SQL:

SELECT Address, State, count(1) As NumEntities 
FROM ( 
    SELECT min(t1.Address) as Address, t1.State 
    FROM TempAllAddresses t1 
    INNER JOIN TempAllAddresses t2 
    ON t1.state = t2.state 
    AND T2.Address LIKE t1.address + '%' 
    GROUP BY t1.State, t2.Address 
) GROUP By State, Address 
0

Avez-vous essayé des fonctions analytiques - ils sont souvent la solution la plus simple. Je ne suis pas familier avec la structure de votre table, mais il devrait être quelque chose comme ceci:

SELECT t1.Address, t1.State, 
COUNT(t2.address) OVER (PARTITION BY t2.state) As NumEntities 
FROM TempAllAddresses t1 
INNER JOIN TempAllAddresses t2 
ON t1.state = t2.state 
AND T2.Address LIKE t1.address + '%' 
GROUP BY t1.State, t1.Address 

Vous pouvez même ajouter ORDER BY dans la clause OVER. Voir Oracle FAQs pour quelques explications.

+0

Je n'ai ' t travaillé avec Oracle befo re donc je ne peux pas dire si ceci fonctionnera là mais dans SQL Server ceci est invalide parce que t2.address et t2.state ne sont pas contenus dans la clause GROUP BY. –

+0

@Jeremy: SQL Server est une chose complètement différente. Cette partie de SQL est spécifique à Oracle. – RapidCoder

+0

Ah ok. Merci pour la clarification. –

1

Voici deux solutions, l'une utilisant CROSS APPLY et l'autre utilisant un INNER JOIN comme vous le vouliez à l'origine. J'espère que ça aide. :)

DECLARE @TempAllAddresses TABLE 
(
    ID INT PRIMARY KEY IDENTITY(1, 1) NOT NULL 
    , [Address] VARCHAR(250) NOT NULL 
    , [State] CHAR(2) NOT NULL 
) 

INSERT INTO @TempAllAddresses 
VALUES ('13 Phoenix', 'NY') 
     , ('13 Phoenix St', 'NY') 
     , ('13 Phoenix Street', 'NY') 
     , ('1845 Test', 'TN') 
     , ('1337 Street', 'WA') 
     , ('1845 T', 'TN') 

SELECT 
    TempAddresses.ID 
    , TempAddresses.[Address] 
    , TempAddresses.[State] 
    , TempAddressesCounted.AddressCount 
FROM @TempAllAddresses TempAddresses 
CROSS APPLY 
(
    SELECT 
     COUNT(*) AS AddressCount 
    FROM @TempAllAddresses TempAddressesApply 
    WHERE TempAddressesApply.[Address] LIKE (TempAddresses.[Address] + '%') 
     AND TempAddressesApply.[State] = TempAddresses.[State] 
) TempAddressesCounted 

SELECT 
    TempAddresses.ID 
    , TempAddresses.[Address] 
    , TempAddresses.[State] 
    , COUNT(*) AS AddressCount 
FROM @TempAllAddresses TempAddresses 
INNER JOIN @TempAllAddresses TempAddressesJoin 
    ON TempAddressesJoin.[Address] LIKE (TempAddresses.[Address] + '%') 
      AND TempAddressesJoin.[State] = TempAddresses.[State] 
GROUP BY TempAddresses.ID 
    , TempAddresses.[Address] 
    , TempAddresses.[State]