market - sql server 2017 vs postgresql 10
Seleccionar filas únicas en un conjunto de dos posibilidades (9)
El problema en sí es simple, pero no puedo encontrar una solución que lo haga en una consulta, y aquí está mi "abstracción" del problema para permitir una explicación más simple:
Dejaré mi stand original, pero aquí hay un conjunto de datos de muestra y el resultado que espero:
Bien, entonces aquí hay algunos datos de muestra, separé pares por una línea en blanco
-------------
| Key | Col | (Together they from a Unique Pair)
--------------
| 1 Foo |
| 1 Bar |
| |
| 2 Foo |
| |
| 3 Bar |
| |
| 4 Foo |
| 4 Bar |
--------------
Y el resultado que esperaría, después de ejecutar la consulta una vez , debe ser capaz de seleccionar este conjunto de resultados en una consulta:
1 - Foo
2 - Foo
3 - Bar
4 - Foo
Explenation original:
Tengo una tabla, llámala TABLE
donde tengo dos columnas, dicen ID
y NAME
que juntas forman la clave principal de la tabla. Ahora quiero seleccionar algo donde ID=1
y luego primero compruebo si puede encontrar una fila donde NAME
tenga el valor "John", si "John" no existe debería buscar una fila donde NAME
es "Bruce" - pero solo devuelve "John" si existen "Bruce" y "John" o solo existe "John", por supuesto.
También tenga en cuenta que debe poder devolver varias filas por consulta que coincidan con los criterios anteriores, pero con diferentes combinaciones de ID / Nombre, por supuesto, y que la explicación anterior sea solo una simplificación del problema real.
Podría estar completamente cegado por mi propio código y línea de pensamiento, pero no puedo resolver esto.
Bien, entonces aquí hay algunos datos de muestra, separé pares por una línea en blanco
-------------
| Key | Col | (Together they from a Unique Pair)
--------------
| 1 Foo |
| 1 Bar |
| |
| 2 Foo |
| |
| 3 Bar |
| |
| 4 Foo |
| 4 Bar |
--------------
Y el resultado que esperaría:
1 - Foo
2 - Foo
3 - Bar
4 - Foo
Lo resolví anteriormente, pero esa pregunta es terriblemente ineficiente para las mesas de lager, de otra manera?
En PostgreSQL, creo que sería esto:
SELECT DISTINCT ON (id) id, name
FROM mytable
ORDER BY id, name = ''John'' DESC;
Actualización - falso tipo antes verdadero - Lo tenía al revés originalmente. Tenga en cuenta que DISTINCT ON es una función de PostgreSQL y no parte de SQL estándar. Lo que sucede aquí es que solo muestra la primera fila para cualquier ID dado que se encuentre. Ya que ordenamos por clima el nombre es John, las filas nombradas John se seleccionarán sobre todos los demás nombres.
Con su segundo ejemplo, sería:
SELECT DISTINCT ON (key) key, col
FROM mytable
ORDER BY key, col = ''Foo'' DESC;
Esto te dará:
1 - Foo
2 - Foo
3 - Bar
4 - Foo
Esto es bastante similar a lo que escribió, pero debe ser bastante rápido ya que NOT EXISTS es más eficiente, en este caso, que NOT IN ...
mysql> select * from foo;
+----+-----+
| id | col |
+----+-----+
| 1 | Bar |
| 1 | Foo |
| 2 | Foo |
| 3 | Bar |
| 4 | Bar |
| 4 | Foo |
+----+-----+
SELECT id
, col
FROM foo f1
WHERE col = ''Foo''
OR ( col = ''Bar'' AND NOT EXISTS( SELECT *
FROM foo f2
WHERE f1.id = f2.id
AND f2.col = ''Foo''
)
);
+----+-----+
| id | col |
+----+-----+
| 1 | Foo |
| 2 | Foo |
| 3 | Bar |
| 4 | Foo |
+----+-----+
Puede usar uniones en lugar del existente y esto puede mejorar el plan de consulta en los casos en que el optimizador no sea lo suficientemente inteligente:
SELECT f1.id
,f1.col
FROM foo f1
LEFT JOIN foo f2
ON f1.id = f2.id
AND f2.col = ''Foo''
WHERE f1.col = ''Foo''
OR ( f1.col = ''Bar'' AND f2.id IS NULL )
Se me ocurrió una solución, pero es algo compleja y lenta, y tampoco se amplía a consultas más avanzadas:
SELECT *
FROM users
WHERE name = "bruce"
OR (
name = "john"
AND NOT id
IN (
SELECT id
FROM posts
WHERE name = "bruce"
)
)
Sin alternativas sin uniones pesadas, etc.?
prueba esto:
select top 1 * from (
SELECT 1 as num, * FROM TABLE WHERE ID = 1 AND NAME = ''John''
union
SELECT 2 as num, * FROM TABLE WHERE ID = 1 AND NAME = ''Bruce''
) t
order by num
Aquí hay un ejemplo que funciona en SQL Server 2005 y versiones posteriores. Es un patrón útil en el que desea elegir la fila superior (o las primeras n filas) según un pedido personalizado. Esto le permitirá no solo elegir entre dos valores con prioridades personalizadas, sino cualquier número. Puede usar la función ROW_NUMBER () y una expresión CASE:
CREATE TABLE T (id int, col varchar(10));
INSERT T VALUES (1, ''Foo'')
INSERT T VALUES (1, ''Bar'')
INSERT T VALUES (2, ''Foo'')
INSERT T VALUES (3, ''Bar'')
INSERT T VALUES (4, ''Foo'')
INSERT T VALUES (4, ''Bar'')
SELECT id,col
FROM
(SELECT id, col,
ROW_NUMBER() OVER (
PARTITION BY id
ORDER BY
CASE col
WHEN ''Foo'' THEN 1
WHEN ''Bar'' THEN 2
ELSE 3 END
) AS RowNum
FROM T
) AS X
WHERE RowNum = 1
ORDER BY id
Puedes unirte a la tabla inicial con un OUTER JOIN como este:
create table #mytest
(
id int,
Name varchar(20)
);
go
insert into #mytest values (1,''Foo'');
insert into #mytest values (1,''Bar'');
insert into #mytest values (2,''Foo'');
insert into #mytest values (3,''Bar'');
insert into #mytest values (4,''Foo'');
insert into #mytest values (4,''Bar'');
go
select distinct
sc.id,
isnull(fc.Name, sc.Name) sel_name
from
#mytest sc
LEFT OUTER JOIN #mytest fc
on (fc.id = sc.id
and fc.Name = ''Foo'')
como eso.
No es necesario que sea demasiado complejo, solo puede usar MAX()
y group by ...
select id, max(col) from foo group by id