Pregunta

Tengo una tabla con la siguiente estructura:

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

Como puede ver, es una tabla desnormalizada, que contiene datos de trabajador y persona (y muchas versiones de una persona) en una tabla. Sin embargo, mi deseo es normalizar esa tabla, ya que la tabla contiene muchos datos (muchas columnas), debo asegurarme de qué columnas deben ir a la tabla de trabajadores y qué columnas a la tabla de personas. El resultado debe ser así:

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

Para hacer eso, necesito analizar qué datos difieren en el alcance de la persona sobre todas las personas únicas (que están separados por personajes en trabajadores). Por ejemplo:

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

En este caso, hay 3 versiones en Persona y 2 versiones de Personb. Los valores de la columna1 son siempre los mismos en todas las versiones de la persona, y podemos mover esa columna al trabajador de la tabla. Pero los valores de la columna 2 y la columna3 cambian en diferentes versiones de la persona, por lo que esos valores deben moverse a la tabla de personas.

No Imagine, tengo alrededor de 10 tablas como esta que deben normalizarse, con aproximadamente 40 columnas en cada una. La tabla Eeach mantiene aproximadamente 500k a 5 m filas.

Necesito un script que me ayude a analizar qué columnas mover a dónde. Necesito un script que genere todas las columnas que cambian en el alcance de una persona única en toda la tabla. Sin embargo, no tengo ideas sobre cómo hacer eso. Experimenté con la función analítica de LAG para comparar con la siguiente fila, pero cómo en el mundo de la salida de las columnas cambió está más allá de mí.

Por favor avise.

Mis mejores deseos, Andrew

¿Fue útil?

Solución

Dado que 10 tablas no son mucho, aquí está (algún tipo de) código 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

Con el esquema de información y las consultas dinámicas, puede hacer el PL/SQL adecuado anterior o tomar la consulta principal y escribirlo en su idioma favorito.

EDITAR:Lo anterior asume que no NULLpecado column_name.

Edit2:Otras variantes de la consulta principal pueden ser

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)

Que devolverá una fila si todos los valores por persona son los mismos. (Esta consulta también tiene problemas con los nulos, pero considero que los nulos un problema separado; siempre puede lanzar un valor nulo a algún valor fuera de dominio para los fines de la consulta anterior)

La consulta anterior también se puede escribir como

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

Que probará varias columnas al mismo tiempo que devuelve verdadero para columnas que pertenecen a 'trabajadores' y falsos para columnas que deberían entrar en 'personas'.

Otros consejos

Gracias, pero lo resolví dejando que Excel creara una serie de seleccionadas sobre la información del esquema de la tabla. La consulta final que generó fue una larga lista de selecciones, pero funciona (aunque se ejecuta más de una hora). La "consulta principal" (en realidad una fórmula en Excel para crear a la consulta del núcleo):

=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")
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top