2010-07-13 2 views
5

Y at-il d'une requête SQL je peux faire cela va générer une séquence linéaire commeExiste-t-il un moyen générique de générer une séquence linéaire arbitraire en SQL?

1, 2, 3, 4, 5, 6, 7 ... x+1 

ou

2, 7, 12, 17, 22 ... 2+5x 

(où chaque nombre est une entrée dans une ligne de la table qui en résulte)

+0

Y at-il une raison de le faire en SQL plutôt qu'au niveau de l'application? – Borealid

+1

@Borealid - Il est souvent utile d'avoir une table de nombres auxiliaires en SQL. –

+0

@Borealid: Si je pouvais générer une telle table, alors je crois que je pourrais l'utiliser pour construire des requêtes plus compliquées; Si je l'ai généré dans l'application, je pense que je serais coincé avec des instructions SQL super longues avec la séquence intégrée en eux. –

Répondre

1

Non. (Sauf si la préconfiguration d'une table de nombres compte comme un moyen générique.)

Dans SQL Server, cela peut être effectué avec un CTE récursif ou généra ing une séquence en utilisant ROW_NUMBER()

0

Utilisez séquence

3

SQL Server et Oracle mettre en œuvre maintenant la norme ANSI ROW_NUMBER() fonction de fenêtrage, mais vous auriez besoin d'une table pour travailler hors de:

SELECT ROW_NUMBER() OVER (ORDER BY ID) AS __ROW, ID, Name 
FROM SomethingWithANameAndAnID 
ORDER BY __ROW; 

Ou vous pouvez utiliser une expression de table commune récursive dans SQL Server (pas sûr si Oracle met en œuvre ce encore):

WITH cte AS 
(
    SELECT 1 AS num 
    UNION ALL 
    SELECT (num + 1) AS num FROM cte 
    WHERE num < @SomeMaximum 
) 
SELECT * FROM cte OPTION (MAXRECURSION 0); 

Notez que sans l'option MAXRECURSION CTE profondeur de récursivité dans MS SQL est limité à 100. (valeur de 0 désactive la limite de récursivité)

0

Dans Oracle, vous pouvez le faire:

select ROWNUM linear_sequence from dual CONNECT BY LEVEL <= x; 

où x est la fin de la séquence.

+0

Ou (pour la série de variantes de l'OP): sélectionnez (ROWNUM-1) * 5 + 2 AS linear_sequence à partir de dual CONNECT BY LEVEL <= x; –

0

Vous pouvez spécifier un incrément lors de la création d'une séquence:

CREATE SEQUENCE mysequence INCREMENT BY 5 START WITH 2; 
2

Si la performance est votre préoccupation, ont cette UDF prêt:

create function [dbo].[Numbers](@count bigint) 
RETURNS TABLE RETURN 
with byte (n) as (select 1 from (VALUES 
     (1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1) 
     ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1) 
     ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1) 
     ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1) 
     ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1) 
     ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1) 
     ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1) 
     ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1) 
     ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1) 
     ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1) 
     ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1) 
     ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1) 
     ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1) 
     ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1) 
     ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1) 
     ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1) 
     ) x(n) ) 
, byte2 (n) as (select 1 from byte a, byte b) 
, byte4 (n) as (select 1 from byte2 a, byte2 b) 
, byte8 (n) as (select 1 from byte4 a, byte4 b) 
select top(@count) n = ROW_NUMBER() over(order by n) from byte8 

Apparemment, généré fonctionne séquence de nombres récursivité uniquement CTE, mais très lent. Ici, nous échangeons du volume de code pour une augmentation énorme des performances. Celui-ci me donne plus de 30 millions de numéros en 8 secondes sur mon PC surchargé. Il peut aller aussi loin que vous le voulez et vous pouvez vous permettre la limite de max bigint.

Il ne touchera pas l'E/S du disque à moins que l'optimiseur l'exclue de la mémoire (rarement pour un scénario raisonnable). Cela évitera également les attentes et les interblocages, contrairement aux solutions basées sur des tables physiques.

Utilisez comme ceci:

select 2 + n*5 from Numbers(100) 

Vous devriez être en mesure de créer une vue comme celui-ci.

Pour ceux qui n'ont pas besoin d'un nombre réel, juste des lignes, en supprimant le nombre row_number l'accélère deux fois.

Inspiré par http://weblogs.sqlteam.com/jamesn/archive/2008/05/29/60612.aspx (Itzik Ben Gan mentionné par S. Neumann). Cette version est livrée avec un plan d'exécution plus simple et rend les bigints possibles, c'est à propos des avantages.

+0

Comparé la performance avec une solution similaire ici http://stackoverflow.com/a/16605089/481812 – Rbjz

+0

Une preuve qu'il peut prendre bigint maintenant 'select count_big (1) de [dbo]. [Nombres] (2147483650)' a pris 2 minutes – Rbjz

Questions connexes