texto - sql substring hasta un caracter
SQL Left Únase solo a la primera coincidencia (6)
Agregue una columna de identidad (PeopleID) y luego use una subconsulta correlacionada para devolver el primer valor para cada valor.
SELECT *
FROM People p
WHERE PeopleID = (
SELECT MIN(PeopleID)
FROM People
WHERE IDNo = p.IDNo
)
Tengo una consulta en contra de un gran número de tablas grandes (filas y columnas) con un número de combinaciones, sin embargo, una de las tablas tiene algunas filas duplicadas de datos que causan problemas para mi consulta. Como este es un feed de solo lectura en tiempo real de otro departamento, no puedo corregir esos datos, sin embargo, estoy tratando de evitar problemas en mi consulta.
Teniendo en cuenta eso, necesito agregar esta basura de datos como un enlace izquierdo a mi buena consulta. El conjunto de datos se ve así:
IDNo FirstName LastName ...
-------------------------------------------
uqx bob smith
abc john willis
ABC john willis
aBc john willis
WTF jeff bridges
sss bill doe
ere sally abby
wtf jeff bridges
...
(alrededor de 2 docenas de columnas y 100K filas)
Mi primer instinto fue realizar un distinto me dio sobre 80K filas:
SELECT DISTINCT P.IDNo
FROM people P
Pero cuando intento lo siguiente, recupero todas las filas:
SELECT DISTINCT P.*
FROM people P
O
SELECT
DISTINCT(P.IDNo) AS IDNoUnq
,P.FirstName
,P.LastName
...etc.
FROM people P
Entonces pensé que haría una función global FIRST () en todas las columnas, sin embargo, eso también parece estar mal. ¿Sintácticamente estoy haciendo algo mal aquí?
Actualización: solo quería señalar: estos registros son duplicados en función de un campo de ID no clave / no indexado enumerado anteriormente. El ID es un campo de texto que, aunque tiene el mismo valor, es un caso diferente al de los otros datos que causan el problema.
Dependiendo de la naturaleza de las filas duplicadas, parece que lo único que desea es tener mayúsculas y minúsculas en esas columnas. Establecer la intercalación en estas columnas debe ser lo que busca:
SELECT DISTINCT p.IDNO COLLATE SQL_Latin1_General_CP1_CI_AS, p.FirstName COLLATE SQL_Latin1_General_CP1_CI_AS, p.LastName COLLATE SQL_Latin1_General_CP1_CI_AS
FROM people P
Después de una cuidadosa consideración, este dillema tiene algunas soluciones diferentes:
Agregar todo Use un agregado en cada columna para obtener el valor de campo más grande o más pequeño. Esto es lo que estoy haciendo ya que se necesitan 2 registros parcialmente llenados y "fusiona" los datos.
http://sqlfiddle.com/#!3/59cde/1
SELECT
UPPER(IDNo) AS user_id
, MAX(FirstName) AS name_first
, MAX(LastName) AS name_last
, MAX(entry) AS row_num
FROM people P
GROUP BY
IDNo
Obtener el primer (o último registro)
http://sqlfiddle.com/#!3/59cde/23
-- ------------------------------------------------------
-- Notes
-- entry: Auto-Number primary key some sort of unique PK is required for this method
-- IDNo: Should be primary key in feed, but is not, we are making an upper case version
-- This gets the first entry to get last entry, change MIN() to MAX()
-- ------------------------------------------------------
SELECT
PC.user_id
,PData.FirstName
,PData.LastName
,PData.entry
FROM (
SELECT
P2.user_id
,MIN(P2.entry) AS rownum
FROM (
SELECT
UPPER(P.IDNo) AS user_id
, P.entry
FROM people P
) AS P2
GROUP BY
P2.user_id
) AS PC
LEFT JOIN people PData
ON PData.entry = PC.rownum
ORDER BY
PData.entry
Prueba esto
SELECT *
FROM people P
where P.IDNo in (SELECT DISTINCT IDNo
FROM people)
Resulta que lo estaba haciendo mal, necesitaba realizar una selección anidada primero de solo las columnas importantes, y hacer una clara selección de eso para evitar que las columnas de basura de datos ''únicos'' corrompan mis buenos datos. Lo siguiente parece haber resuelto el problema ... pero intentaré con el conjunto de datos completo más adelante.
SELECT DISTINCT P2.*
FROM (
SELECT
IDNo
, FirstName
, LastName
FROM people P
) P2
Aquí hay algunos datos de reproducción solicitados: http://sqlfiddle.com/#!3/050e0d/3
CREATE TABLE people
(
[entry] int
, [IDNo] varchar(3)
, [FirstName] varchar(5)
, [LastName] varchar(7)
);
INSERT INTO people
(entry,[IDNo], [FirstName], [LastName])
VALUES
(1,''uqx'', ''bob'', ''smith''),
(2,''abc'', ''john'', ''willis''),
(3,''ABC'', ''john'', ''willis''),
(4,''aBc'', ''john'', ''willis''),
(5,''WTF'', ''jeff'', ''bridges''),
(6,''Sss'', ''bill'', ''doe''),
(7,''sSs'', ''bill'', ''doe''),
(8,''ssS'', ''bill'', ''doe''),
(9,''ere'', ''sally'', ''abby''),
(10,''wtf'', ''jeff'', ''bridges'')
;
distinct
no es una función. Siempre opera en todas las columnas de la lista de selección.
Su problema es un problema típico de "mayor N por grupo" que puede resolverse fácilmente utilizando una función de ventana:
select ...
from (
select IDNo,
FirstName,
LastName,
....,
row_number() over (partition by lower(idno) order by firstname) as rn
from people
) t
where rn = 1;
Usando la cláusula order by
, puede seleccionar cuál de los duplicados desea elegir.
Lo anterior se puede usar en una combinación a la izquierda:
select ...
from x
left join (
select IDNo,
FirstName,
LastName,
....,
row_number() over (partition by lower(idno) order by firstname) as rn
from people
) p on p.idno = x=idno and p.rn = 1
where ...