mysql - varios - sentencias sql




¿Cómo seleccionar la fila nth en una tabla de base de datos SQL? (20)

Estoy interesado en aprender algunas maneras (idealmente) independientes de la base de datos de seleccionar la fila n de una tabla de base de datos. También sería interesante ver cómo se puede lograr esto utilizando la funcionalidad nativa de las siguientes bases de datos:

  • servidor SQL
  • MySQL
  • PostgreSQL
  • SQLite
  • Oráculo

Actualmente estoy haciendo algo como lo siguiente en SQL Server 2005, pero estaría interesado en ver otros enfoques más agnósticos:

WITH Ordered AS (
SELECT ROW_NUMBER() OVER (ORDER BY OrderID) AS RowNumber, OrderID, OrderDate
FROM Orders)
SELECT *
FROM Ordered
WHERE RowNumber = 1000000

Crédito por el SQL anterior: Weblog de Firoz Ansari

Actualización: Vea la respuesta de Troels Arvin con respecto al estándar SQL. Troels, ¿tienes algún enlace que podamos citar?


SERVIDOR SQL

Seleccione n 'th registro de arriba

SELECT * FROM (
SELECT 
ID, NAME, ROW_NUMBER() OVER(ORDER BY ID) AS ROW
FROM TABLE 
) AS TMP 
WHERE ROW = n

seleccione n 'th registro desde la parte inferior

SELECT * FROM (
SELECT 
ID, NAME, ROW_NUMBER() OVER(ORDER BY ID DESC) AS ROW
FROM TABLE 
) AS TMP 
WHERE ROW = n

1 pequeño cambio: n-1 en lugar de n.

select *
from thetable
limit n-1, 1

Aquí está una solución rápida de su confusión.

SELECT * FROM table ORDER BY `id` DESC LIMIT N, 1

Aquí puede obtener la última fila llenando N = 0, la segunda última por N = 1, la cuarta última llenando N = 3 y así sucesivamente.

Esta es una pregunta muy común en la entrevista y es muy simple.

Además, si desea Cantidad, ID o algún Orden de Clasificación Numérico, puede utilizar la función CAST en MySQL.

SELECT DISTINCT (`amount`) FROM cart ORDER BY CAST( `amount` AS SIGNED ) DESC LIMIT 4 , 1

Aquí, al llenar N = 4, podrá obtener el quinto último registro del monto más alto de la tabla CARTA. Puede ajustar el campo y el nombre de la tabla y proponer una solución.


Aquí hay una versión genérica de un sproc que escribí recientemente para Oracle que permite la paginación / clasificación dinámica - HTH

-- p_LowerBound = first row # in the returned set; if second page of 10 rows,
--                this would be 11 (-1 for unbounded/not set)
-- p_UpperBound = last row # in the returned set; if second page of 10 rows,
--                this would be 20 (-1 for unbounded/not set)

OPEN o_Cursor FOR
SELECT * FROM (
SELECT
    Column1,
    Column2
    rownum AS rn
FROM
(
    SELECT
        tbl.Column1,
        tbl.column2
    FROM MyTable tbl
    WHERE
        tbl.Column1 = p_PKParam OR
        tbl.Column1 = -1
    ORDER BY
        DECODE(p_sortOrder, 'A', DECODE(p_sortColumn, 1, Column1, 'X'),'X'),
        DECODE(p_sortOrder, 'D', DECODE(p_sortColumn, 1, Column1, 'X'),'X') DESC,
        DECODE(p_sortOrder, 'A', DECODE(p_sortColumn, 2, Column2, sysdate),sysdate),
        DECODE(p_sortOrder, 'D', DECODE(p_sortColumn, 2, Column2, sysdate),sysdate) DESC
))
WHERE
    (rn >= p_lowerBound OR p_lowerBound = -1) AND
    (rn <= p_upperBound OR p_upperBound = -1);

Contrariamente a lo que afirman algunas de las respuestas, el estándar SQL no guarda silencio con respecto a este tema.

Desde SQL: 2003, ha podido usar "funciones de ventana" para omitir filas y limitar los conjuntos de resultados.

Y en SQL: 2008, se había agregado un enfoque un poco más simple, utilizando
OFFSET skip ROWS FETCH FIRST n ROWS ONLY

Personalmente, no creo que la adición de SQL: 2008 fuera realmente necesaria, por lo que si fuera ISO, lo habría mantenido fuera de un estándar ya bastante grande.


Cuando solíamos trabajar en MSSQL 2000, hicimos lo que llamamos "triple-flip":

Editado

DECLARE @InnerPageSize int
DECLARE @OuterPageSize int
DECLARE @Count int

SELECT @Count = COUNT(<column>) FROM <TABLE>
SET @InnerPageSize = @PageNum * @PageSize
SET @OuterPageSize = @Count - ((@PageNum - 1) * @PageSize)

IF (@OuterPageSize < 0)
    SET @OuterPageSize = 0
ELSE IF (@OuterPageSize > @PageSize)
    SET @OuterPageSize = @PageSize

DECLARE @sql NVARCHAR(8000)

SET @sql = 'SELECT * FROM
(
    SELECT TOP ' + CAST(@OuterPageSize AS nvarchar(5)) + ' * FROM
    (
        SELECT TOP ' + CAST(@InnerPageSize AS nvarchar(5)) + ' * FROM <TABLE> ORDER BY <column> ASC
    ) AS t1 ORDER BY <column> DESC
) AS t2 ORDER BY <column> ASC'

PRINT @sql
EXECUTE sp_executesql @sql

No era elegante, y no era rápido, pero funcionó.


En Sybase SQL Anywhere:

SELECT TOP 1 START AT n * from table ORDER BY whatever

No olvides el ORDEN POR o no tiene sentido.


Hay formas de hacer esto en partes opcionales del estándar, pero muchas bases de datos admiten su propia forma de hacerlo.

Un sitio realmente bueno que habla sobre esto y otras cosas es http://troels.arvin.dk/db/rdbms/#select-limit .

Básicamente, PostgreSQL y MySQL son compatibles con lo no estándar:

SELECT...
LIMIT y OFFSET x 

Oracle, DB2 y MSSQL son compatibles con las funciones de ventanas estándar:

SELECT * FROM (
  SELECT
    ROW_NUMBER() OVER (ORDER BY key ASC) AS rownumber,
    columns
  FROM tablename
) AS foo
WHERE rownumber <= n

(que acabo de copiar del sitio vinculado anteriormente porque nunca uso esos DB)

Actualización: a partir de PostgreSQL 8.4, las funciones de ventanas estándar son compatibles, así que espere que el segundo ejemplo funcione también para PostgreSQL.


La sintaxis de LIMIT / OFFSET en PostgreSQL es:

SELECT
    *
FROM
    mytable
ORDER BY
    somefield
LIMIT 1 OFFSET 20;

Este ejemplo selecciona la fila 21 OFFSET 20 está diciendo a Postgres que se salte los primeros 20 registros. Si no especifica una cláusula ORDER BY , no hay garantía de qué registro recibirá, lo que rara vez es útil.

Al parecer, el estándar SQL no dice nada sobre el problema del límite fuera de las funciones de ventanas locas, por lo que todo el mundo lo implementa de manera diferente.


Me parece que, para ser eficiente, necesita 1) generar un número aleatorio entre 0 y uno menos que el número de registros de la base de datos, y 2) poder seleccionar la fila en esa posición. Desafortunadamente, las diferentes bases de datos tienen diferentes generadores de números aleatorios y diferentes maneras de seleccionar una fila en una posición en un conjunto de resultados; por lo general, especifica cuántas filas omitir y cuántas filas desea, pero se hace de manera diferente para diferentes bases de datos. Aquí hay algo que me funciona en SQLite:

select * 
from Table 
limit abs(random()) % (select count(*) from Words), 1;

Depende de poder usar una subconsulta en la cláusula límite (que en SQLite es LIMIT <recs to skip>, <recs to take>) La selección del número de registros en una tabla debe ser particularmente eficiente, siendo parte de la base de datos metadatos, pero eso depende de la implementación de la base de datos. Además, no sé si la consulta realmente compilará el conjunto de resultados antes de recuperar el registro Nth, pero espero que no sea necesario. Tenga en cuenta que no estoy especificando una cláusula "ordenar por". Podría ser mejor "ordenar por" algo así como la clave principal, que tendrá un índice: obtener el registro enésimo de un índice podría ser más rápido si la base de datos no puede obtener el registro enésimo de la misma base de datos sin construir el conjunto de resultados .


No estoy seguro de nada del resto, pero sé que SQLite y MySQL no tienen ningún orden de filas "predeterminado". En esos dos dialectos, al menos, el siguiente fragmento de código toma la 15ª entrada de the_table, ordenada por la fecha / hora en que se agregó:

SELECT * FROM the_table ORDER BY added DESC LIMIT 1,15

(por supuesto, deberías tener un campo DATETIME agregado, y configurarlo en la fecha / hora en que se agregó la entrada ...)


Oráculo:

select * from (select foo from bar order by foo) where ROWNUM = x

Para el servidor SQL, lo siguiente devolverá la primera fila de la tabla de resultados.

declare @rowNumber int = 1;
    select TOP(@rowNumber) * from [dbo].[someTable];
EXCEPT
    select TOP(@rowNumber - 1) * from [dbo].[someTable];

Puedes recorrer los valores con algo como esto:

WHILE @constVar > 0
BEGIN
    declare @rowNumber int = @consVar;
       select TOP(@rowNumber) * from [dbo].[someTable];
    EXCEPT
       select TOP(@rowNumber - 1) * from [dbo].[someTable];  

       SET @constVar = @constVar - 1;    
END;

Pero realmente, ¿no es todo esto simplemente trucos de sala para un buen diseño de base de datos en primer lugar? Las pocas veces que necesité una funcionalidad como esta fue para hacer una consulta simple para hacer un informe rápido. Para cualquier trabajo real, el uso de trucos como estos está invitando a problemas. Si se necesita seleccionar una fila en particular, simplemente tenga una columna con un valor secuencial y termine con ella.


SQL 2005 y superior tiene esta característica incorporada. Utilice la función ROW_NUMBER (). Es excelente para páginas web con un estilo de navegación << Anterior y Siguiente >>:

Sintaxis:

SELECT
    *
FROM
    (
        SELECT
            ROW_NUMBER () OVER (ORDER BY MyColumnToOrderBy) AS RowNum,
            *
        FROM
            Table_1
    ) sub
WHERE
    RowNum = 23

Sospecho que esto es tremendamente ineficiente pero es un enfoque bastante simple, que funcionó en un pequeño conjunto de datos en el que lo probé.

select top 1 field
from table
where field in (select top 5 field from table order by field asc)
order by field desc

Esto obtendría el quinto artículo, cambia el segundo número superior para obtener un noveno elemento diferente

Solo servidor SQL (creo) pero debería funcionar en versiones anteriores que no admiten ROW_NUMBER ().


Verifíquelo en SQL Server:

Select top 10 * From emp 
EXCEPT
Select top 9 * From emp

Esto te dará la décima fila de la tabla emp!


increíble que puedes encontrar un motor SQL ejecutando este ...

WITH sentence AS
(SELECT 
    stuff,
    row = ROW_NUMBER() OVER (ORDER BY Id)
FROM 
    SentenceType
    )
SELECT
    sen.stuff
FROM sentence sen
WHERE sen.row = (ABS(CHECKSUM(NEWID())) % 100) + 1

SELECT * FROM emp a
WHERE  n = (SELECT COUNT( _rowid)
              FROM emp b
             WHERE a. _rowid >= b. _rowid);

select * from 
(select * from ordered order by order_id limit 100) x order by 
x.order_id desc limit 1;

Primero seleccione las primeras 100 filas ordenando en forma ascendente y luego seleccione la última fila ordenando en forma descendente y límite a 1. Sin embargo, esta es una declaración muy costosa ya que accede a los datos dos veces.





postgresql