2010-05-10 19 views
5

He estado golpeando mi cabeza en el escritorio tratando de resolver esto. Tengo una tabla que almacena la información del trabajo y las razones por las que un trabajo no se completa. Las razones son numéricas, 01,02,03, etc. Puede tener dos motivos para un trabajo pendiente. Si selecciona dos razones, se almacenan en la misma columna, separadas por una coma. Este es un ejemplo de la JOBID tabla:Consulta SQL con múltiples valores en una columna

Job_Number  User_Assigned  PendingInfo 

1    user1    01,02 

Hay otra tabla llamada Pendiente, que almacena lo que esos valores representan en realidad. 01 = información insuficiente, 02 = tiempo insuficiente, 03 = espera de revisión. Ejemplo:

Pending_Num PendingWord 

01    Not Enough Info 
02    Not Enough Time 

Lo que estoy tratando de hacer es consultar la base de datos para darme todos los números de trabajo, usuarios, pendinginfo, y la razón pendiente. Puedo descifrar el primer valor, pero no puedo descifrar cómo hacer el segundo. Lo que mis habilidades limitadas tienen hasta el momento:

select Job_number,user_assigned,SUBSTRING(pendinginfo,0,3),pendingword 
from jobid,pending 
where 
    SUBSTRING(pendinginfo,0,3)=pending.pending_num and 
    pendinginfo!='00,00' and 
    pendinginfo!='NULL' 

lo que me gustaría ver en este ejemplo sería:

Job_Number User_Assigned PendingInfo PendingWord  PendingInfo PendingWord 

1   User1   01   Not Enough Info 02   Not Enough Time 

Gracias de antemano

+0

¿Cambiar el esquema es una opción? Esta relación debería ser realmente una tabla de asignación o una columna de razón secundaria. –

+0

Base de datos 101 - ** primera ** forma normal (1NF): cada celda de fila/columna debe contener como máximo ** un valor **. –

Respuesta

2

Si cambia el esquema es una opción (que probablemente debería ser) ¿no debería implementar una relación de muchos a muchos aquí para que tenga una tabla puente entre los dos elementos? De esta manera, se podría almacenar el número y su redacción en una mesa, puestos de trabajo en otros, y "razones de fracaso para puestos de trabajo" en la tabla de puenteo ...

5

Realmente no debería almacenar varios elementos en una columna si su SQL alguna vez va a querer procesarlos individualmente. La "gimnasia SQL" que tienes que realizar en esos casos son tanto hacks feos como degradadores de rendimiento.

La solución ideal es la de dividir los elementos individuales en columnas separadas y, por 3NF, mover las columnas a una tabla separada como filas si realmente desea hacerlo adecuadamente (pero pequeños pasos son probablemente bien si' asegúrese de que nunca haya más de dos razones en el corto-mediano plazo).

A continuación, sus consultas serán más simples y rápidas.


Sin embargo, si eso no es una opción, puede utilizar la gimnasia SQL anteriormente mencionados para hacer algo como:

where find (',' |fld| ',', ',02,') > 0 

asumiendo que su lenguaje SQL tiene una función de búsqueda de cadenas (find en este caso , pero creo que charindex para SQLServer).

Esto asegurará que todas las subcolumnas comiencen y comiencen con una coma (coma más campo más coma) y busque un valor deseado específico (con las comas en cada lado para asegurarse de que sea una coincidencia completa de subcolumna).


Si no puede control de lo que pone la aplicación de esa columna, optaría por la solución DBA - soluciones DBA se definen como aquellos que un DBA tiene que hacer para evitar las deficiencias de sus usuarios :-).

Crea dos nuevas columnas en esa tabla y crea un disparador de inserción/actualización que las rellenará con las dos razones que un usuario coloca en la columna original.

Luego consulta esas dos nuevas columnas para obtener valores específicos en lugar de intentar dividir la columna anterior.

Esto significa que el costo de dividir es solo en la inserción/actualización de fila, no en cada 'selección individual', amortizando ese costo eficientemente.


Aún así, mi respuesta es que vuelva a hacer el esquema. Esa será la mejor manera a largo plazo en términos de velocidad, consultas legibles y capacidad de mantenimiento.

+0

Sí, recrear sería la mejor manera, pero esa no es una opción en este momento. Esta es la situación con la que tengo que trabajar. Lo siento, se olvidó de mencionar que esto es MS SQL 2008 – lp1

+0

Entonces dile a tus jefes que es una mala idea, entonces prueba la opción 'charindex'. Y, si la actuación es una mierda, puedes decirle a tus jefes que tenías razón y que eran idiotas, con suerte con más tacto de lo que normalmente soy capaz :-) – paxdiablo

+0

Voy a intentar con ese charindex. – lp1

5

Espero que solo estés manteniendo el código y no sea una implementación completamente nueva.
Por favor, considere utilizar un enfoque diferente utilizando una mesa de soporte de esta manera:

JOBS TABLE 
jobID | userID 
-------------- 
1  | user13 
2  | user32 
3  | user44 
-------------- 

PENDING TABLE 
pendingID | pendingText 
--------------------------- 
01  | Not Enough Info 
02  | Not Enough Time 
--------------------------- 

JOB_PENDING TABLE 
jobID | pendingID 
----------------- 
1  | 01 
1  | 02 
2  | 01 
3  | 03 
3  | 01 
----------------- 

se puede consultar fácilmente esta tablas usando JOIN o subconsultas.
Si necesita retrocompatibilidad en su software, puede agregar una vista para alcanzar este objetivo.

1

Tener un vistazo a una pregunta similar que respondió here

;WITH Numbers AS 
( 
    SELECT ROW_NUMBER() OVER(ORDER BY (SELECT 0)) AS N 
    FROM JobId 
), 
Split AS 
( 
    SELECT JOB_NUMBER, USER_ASSIGNED, SUBSTRING(PENDING_INFO, Numbers.N, CHARINDEX(',', PENDING_INFO + ',', Numbers.N) - Numbers.N) AS PENDING_NUM 
    FROM JobId 
    JOIN Numbers ON Numbers.N <= DATALENGTH(PENDING_INFO) + 1 
    AND SUBSTRING(',' + PENDING_INFO, Numbers.N, 1) = ',' 
) 
SELECT * 
FROM Split JOIN Pending ON Split.PENDING_NUM = Pending.PENDING_NUM 

La idea básica es que hay que multiplicar cada fila tantas veces como hay PENDING_NUM s. A continuación, extraer la parte apropiada de la cadena

3

tengo unas tablas como:

Events 
--------- 
eventId int 
eventTypeIds nvarchar(50) 
... 

EventTypes 
-------------- 
eventTypeId 
Description 
... 

Cada evento puede tener múltiples eventtypes especificados.

Todo lo que hago es escribir 2 procedimientos en mi código de sitio, no el código SQL

  1. Un procedimiento convierte el campo de tabla (eventTypeIds) valor como "3,4,15,6" en una matriz de ViewState , entonces puedo usarlo en cualquier parte del código.

  2. Este procedimiento hace lo contrario Recoge todas las opciones de su comprobado y lo convierte en

0

Aunque estoy de acuerdo con la perspectiva de DBA no almacenar varios valores en un solo campo es factible, como bramido, práctico para la lógica de la aplicación y algunos problemas de rendimiento.

Supongamos que tiene 10000 grupos de usuarios, cada uno con un promedio de 1000 miembros. Es posible que desee tener una tabla user_groups con columnas como groupID e membersID. Su columna membersID puede ser poblada así: (', 10,2001,20003,333,4520,') cada número siendo un memberID, todos separados por una coma. Agregue también una coma al comienzo y al final de los datos. Entonces su selección usaría como '%, someID,%'.

Si no puede cambiar sus datos ('01, 02,03 ') o similares, supongamos que quiere filas que contengan 01, todavía puede usar "seleccionar ... ME GUSTA '01,%' O '%, 01' O '%, 01,%' "que asegurará que coincida si al inicio, final o dentro, mientras se evita un número similar (es decir: 101).

Cuestiones relacionadas