3

J'ai une table avec la structure suivante:Normaliser une table: trouver des colonnes uniques sur la série de lignes (Oracle 10.x)

WorkerPersons 
------------------------------- 
ID   (PK) 
PersonID (Indicates which version of Person the record describes) 
SomeColumn1 (data specific to Worker) 
SomeColumn2 (data specific to Person) 
.... 
SomeColumnN 
------------------------------- 

Comme vous pouvez le voir, il est une table dénormalisé, qui détient à la fois des travailleurs et Personne (et de nombreuses versions d'une personne) dans une table. Mon souhait est de normaliser cette table, cependant, comme la table contient beaucoup de données (beaucoup de nombreuses colonnes), je dois être sûr que les colonnes devraient aller à la table Workers et quelles colonnes à la table Persons. Le résultat devrait être comme ceci:

Workers     Persons 
----------------------- --------------------- 
ID      ID 
PersonID (now a FK)  PersonColumn1 
WorkerColumn1   PersonColumn2 
WorkerColumn2   ... 
...      PersonColumnN 
WorkerColumnN 
----------------------- --------------------- 

Pour ce faire, je dois analyser les données qui a une portée différente de la personne sur toutes les personnes uniques (Wich sont séparés par PersonID en WorkerPersons). Par exemple:

WorkerPersons 
------------------------------------------------------- 
ID  PersonID  Column1  Column2  Column3 
------------------------------------------------------- 
1  PersonA  10.1   John Doe  Single 
2  PersonA  10.1   John Doe  Single 
3  PersonA  10.1   John Doe  Married 
4  PersonB  09.2   Sully  Single 
5  PersonB  09.2   Sullivan  Single 

Dans ce cas, il existe 3 versions sur PersonA et 2 versions de PersonB. Les valeurs Column1 sont toujours les mêmes sur toutes les versions de Person, et nous pouvons déplacer cette colonne vers la table Worker. Mais les valeurs Colonne 2 et Colonne3 changent sur différentes versions de la personne, donc ces valeurs doivent être déplacées vers la table Person.

Non imaginez, j'ai environ 10 tables comme ça qui ont besoin d'être normalisées, avec environ 40 colonnes dans chacune. La table Eeach contient environ 500k à 5m lignes.

J'ai besoin d'un script qui m'aide à analyser les colonnes à déplacer où. J'ai besoin d'un script qui affiche toutes les colonnes qui changent dans la portée de la personne unique sur toute la table. Je n'ai pas d'idées cependant comment faire cela. J'ai expérimenté avec la fonction analytique LAG pour comparer avec la rangée suivante mais comment dans le monde pour sortir les colonnes changées est au-delà de moi.

Veuillez nous aviser.

Meilleurs voeux, Andrew

Répondre

3

Depuis 10 tables ne sont pas beaucoup, voici (une sorte de) code pseudo

for each table_name in tables 
    for each column_name in columns 
    case (exists (select 1 
      from table_name 
      group by PersonID 
      having min(column_name) = max(column_name)) 
     when true then 'Worker' 
     when false then 'Person' 
    end case 
    end for 
end for 

avec le schéma de l'information et des requêtes dynamiques que vous pouvez faire ce qui précède bon PL/SQL ou prenez la requête de base et le script dans votre langue préférée.

EDIT: Ce qui précède suppose aucun NULL s en column_name.

EDIT2: D'autres variantes de la requête de base peut être

SELECT 1 
FROM 
(SELECT COUNT(DISTINCT column_name) AS distinct_values_by_pid 
FROM table_name 
GROUP BY PersonID) T 
HAVING MIN(distinct_values_by_pid) = MAX(distinct_values_by_pid) 

qui retourne une ligne si toutes les valeurs par PersonID sont les mêmes. (cette requête a également des problèmes avec NULLS, mais je considère NULLs un problème distinct, vous pouvez toujours convertir une valeur NULL à une valeur hors domaine pour la requête ci-dessus)

La requête ci-dessus peut également être écrite comme

SELECT MIN(c1)=MAX(c1), MIN(c2)=MAX(c2), ... 
FROM 
(SELECT COUNT(DISTINCT column_name_1) AS c1, COUNT(DISTINCT column_name_2) AS c2, ... 
FROM table_name 
GROUP BY PersonID) T 

qui testera plusieurs colonnes en même temps le retour vrai pour les colonnes qui appartiennent aux « travailleurs » et faux pour les colonnes qui devraient aller dans des « personnes ».

1

Merci, mais je l'ai résolu en laissant Excel créer une série de sélections sur les informations de schéma de table. La dernière requête générée était une longue liste de sélections, mais cela fonctionne (bien qu'elle dure plus d'une heure). La "requête de base" (en fait une formule dans Excel pour créer une requête de base):

=IF(AND(C17<>"CLOB";C17<>"NCLOB");"SELECT '"&A17&".'||initcap('"&B17&"') description, 
decode(count(*),0,'SAME OVE VERSIONS','DIFFERENT OVER VERSIONS') values FROM (SELECT 
objektid, count(DISTINCT nvl("&B17&","&IF(C17="DATE";"'01.02.0004'";IF(C17="VARCHAR2" 
;"'!#¤¤%¤(%#¤%AS'";"-1234561"))&")) OVER (PARTITION BY objectid) arv FROM "&A17&") 
WHERE number > 1 union all";"SELECT '"&A17&".'||initcap('"&B17&"') description, 'CLOB 
field' values from dual union all") 
Questions connexes