2009-02-03 17 views
2

J'ai un ensemble d'enregistrements dans ma table MS SQL. Avec Date comme clé primaire. Mais les dates sont seulement pour les jours ouvrables et non les jours continus. Par exemple:Comment obtenir l'enregistrement suivant dans la table SQL

1/3/2000 12:00:00 AM 5209,540000000 5384,660000000 5209,540000000 5375,110000000 1/4/2000 12:00:00 AM 5533,980000000 5533,980000000 5376,430000000 5491,010000000 1/5/2000 12:00:00 AM 5265,090000000 5464,350000000 5184,480000000 5357,000000000 1/6/2000 12:00:00 AM 5424,210000000 5489,860000000 5391,330000000 5421,530000000 1/7/2000 12:00:00 AM 5358,280000000 5463,250000000 5330,580000000 5414,480000000 1/10/2000 12:00:00 AM 5617,590000000 5668,280000000 5459,970000000 5518.390000000 1/11/2000 12:00:00 AM 5513.040000000 5537.690000000 5221.280000000 5296.300000000 1/12/2000 12:00:00 AM 5267.850000000 5494.300000000 5267.850000000 5491.200000000 J'essaie d'introduire une nouvelle colonne dans la table et la valeur doit être la valeur de la 3ème colonne moins la valeur de la 3ème colonne du jour ouvrable précédent. S'il vous plaît aidez-moi à écrire une telle requête. Je trouve cela difficile car les dates ne sont pas présentes pour les fins de semaine.

Répondre

2

Il y a plusieurs façons de procéder. En voici un.

CREATE TABLE MyTable 
(
    MyDate datetime NOT NULL PRIMARY KEY, 
    Col2 decimal(14,4) NOT NULL, 
    Col3 decimal(14,4) NOT NULL, 
    Col4 decimal(14,4) NOT NULL, 
    Col5 decimal(14,4) NOT NULL 
) 
GO 

INSERT INTO MyTable 
SELECT '1/3/2000 12:00:00 AM', 5209.540000000, 5384.660000000, 5209.540000000, 5375.110000000 
UNION ALL 
SELECT '1/4/2000 12:00:00 AM', 5533.980000000, 5533.980000000, 5376.430000000, 5491.010000000 
UNION ALL 
SELECT '1/5/2000 12:00:00 AM', 5265.090000000, 5464.350000000, 5184.480000000, 5357.000000000 
UNION ALL 
SELECT '1/6/2000 12:00:00 AM', 5424.210000000, 5489.860000000, 5391.330000000, 5421.530000000 
UNION ALL 
SELECT '1/7/2000 12:00:00 AM', 5358.280000000, 5463.250000000, 5330.580000000, 5414.480000000 
UNION ALL 
SELECT '1/10/2000 12:00:00 AM', 5617.590000000, 5668.280000000, 5459.970000000, 5518.390000000 
UNION ALL 
SELECT '1/11/2000 12:00:00 AM', 5513.040000000, 5537.690000000, 5221.280000000, 5296.300000000 
UNION ALL 
SELECT '1/12/2000 12:00:00 AM', 5267.850000000, 5494.300000000, 5267.850000000, 5491.200000000 
GO 

CREATE VIEW MyView 
AS 
SELECT T1.*, 
    CalculatedColumn = Col3 - 
     (SELECT Col3 FROM MyTable Q2 
     WHERE Q2.MyDate = (SELECT MAX(Q1.MyDate) 
          FROM MyTable Q1 
          WHERE Q1.MyDate < T1.MyDate) 
    ) 
FROM MyTable T1 
GO 

SELECT * FROM MyView 
GO 

Résultats

MyDate     Col2  Col3  Col4  Col5  CalculatedColumn 
----------------------- --------- --------- --------- --------- ---------------- 
2000-01-03 00:00:00.000 5209.5400 5384.6600 5209.5400 5375.1100 NULL 
2000-01-04 00:00:00.000 5533.9800 5533.9800 5376.4300 5491.0100 149.3200 
2000-01-05 00:00:00.000 5265.0900 5464.3500 5184.4800 5357.0000 -69.6300 
2000-01-06 00:00:00.000 5424.2100 5489.8600 5391.3300 5421.5300 25.5100 
2000-01-07 00:00:00.000 5358.2800 5463.2500 5330.5800 5414.4800 -26.6100 
2000-01-10 00:00:00.000 5617.5900 5668.2800 5459.9700 5518.3900 205.0300 
2000-01-11 00:00:00.000 5513.0400 5537.6900 5221.2800 5296.3000 -130.5900 
2000-01-12 00:00:00.000 5267.8500 5494.3000 5267.8500 5491.2000 -43.3900 
+0

Vous pouvez probablement optimiser la clause inner where où restreindre les lignes de Q1. Vous savez que la rangée précédente sera au plus 2 ou 3 jours plus tôt. –

+0

@Mike Il effectue un RECHERCHE D'INDICE CLUSTERED, ce qui est très efficace. SQL Server est généralement assez bon pour l'auto-optimisation. – beach

1

Vous devez diviser en 2 parties. La première consiste à mettre à jour vos données existantes, et la seconde consiste à s'assurer que toutes les nouvelles données ont la valeur ajoutée correcte.

Pour la première partie, pensez à utiliser un CURSEUR. Il faudra probablement un certain temps pour s'exécuter, mais au moins, vous ne l'exécutez qu'une seule fois. Utilisez un curseur comme une boucle FOR; parcourez chaque ligne de vos données en ignorant la première ligne (puisque vous n'avez pas spécifié comment calculer la valeur de la nouvelle colonne lorsqu'il n'y a pas de date précédente). Très probablement, vous devriez trier par date ascendant, juste au cas où. Lorsque vous parcourez, utilisez des variables pour stocker les valeurs de cette ligne. Lorsque vous effectuez une boucle, copiez ces variables dans les versions de lignes précédentes avant d'obtenir la nouvelle ligne. Par exemple, vous avez une variable appelée 'Col3' et une autre appelée 'lastCol3'. Avant de passer à la ligne suivante (c'est-à-dire que le curseur se déplace vers la ligne suivante), copiez la valeur de col3 dans lastCol3 et vous obtenez la nouvelle valeur pour col3. Vous avez maintenant votre valeur actuelle et précédente par ligne, et vous pouvez appeler 'update' pour mettre à jour la nouvelle colonne. Pour les nouvelles données à venir, vous devez vous assurer que la nouvelle valeur est fournie, ou si vous voulez que SQL Server le fasse, utilisez une procédure stockée qui sélectionne la ligne la plus récente, col3, et utilise la valeur pour calculer le nouvelle valeur avant d'insérer dans la table.

1

Utilisez un autojointure et une déclaration de cas qui profite de son SQLServers de fonction intégrée Date datepart(dw,@Date).

Je me sens obligé de noter que faire une telle transformation en premier lieu est probablement une mauvaise idée.

Questions connexes