3

Ich habe eine Tabelle, in der einige Werte für Monate und Jahre gespeichert sind.Wählen Sie N Zeilen vor und N Zeilen nach dem Datensatz

Beispiel:

Month | Year | Value 
    1 | 2013 | 1.86 
    2 | 2013 | 2.25 
    3 | 2013 | 2.31 
    ... 
    3 | 2016 | 1.55 
    4 | 2016 | 1.78 

Monat und Jahr Kombination ist ein komplexer Primärschlüssel. Es ist garantiert, dass alle Werte für alle vergangenen Jahre in der Tabelle vorhanden sind.

Benutzer kann bestimmten Monat und bestimmtes Jahr auswählen. Nehmen wir an, der Benutzer hat 2014 als Jahr und 6 als Monat ausgewählt. Ich muss 15 Zeilen vor und 15 Zeilen nach der ausgewählten Kombination anzeigen.

Wenn aber nicht genügend Zeilen (weniger als 15) nach der ausgewählten Kombination vorhanden sind, muss ich vorher mehr Zeilen abrufen.

Grundsätzlich brauche ich nur 31 Zeilen (immer 31, es sei denn, es gibt nicht genug Zeilen in der gesamten Tabelle) der Daten, wo die ausgewählte Kombination so nahe wie möglich an der Mitte sein wird.

Was ist der richtige Weg, das zu tun?

Derzeit bin ich mit diesem fest:

;WITH R(N) AS 
(
    SELECT 0 
    UNION ALL 
    SELECT N+1 
    FROM R 
    WHERE N < 29 
) 
SELECT * FROM MyTable e 
LEFT OUTER JOIN (
    SELECT N, MONTH(DATEADD(MONTH,-N,iif(@year != Year(GETDATE()), DATEFROMPARTS(@year, 12, 31) ,GETDATE()))) AS [Month], 
    YEAR(DATEADD(MONTH,-N,iif(@year!= Year(GETDATE()), DATEFROMPARTS(@year, 12, 31) ,GETDATE()))) AS [Year] 
FROM R) s 
ON s.[Year] = e.[Year] AND s.[Month] = e.[Month] 
WHERE s.[N] is not null 

Das ist nicht wirklich das, was ich tun möchte, da es im nächsten Jahr Monate abschneidet nur

+0

, welche SQL-Server-Version zu funktionieren? – Mihai

+0

sql server 2012 – Coffka

+0

möchten Sie vielleicht dies überprüfen http://StackOverflow.com/Questions/2135418/equivalent-of-limit-and-offset-for-sql-server –

Antwort

1

Wie wäre es einfach etwas wie folgt aus:

;WITH CTE AS (
    SELECT Month 
     ,Year 
     ,Value 
     ,ROW_NUMBER() OVER (ORDER BY Year, Month) rn 
    FROM MyTable 
    ) 
SELECT Month 
    ,Year 
    ,Value 
FROM CTE 
WHERE rn >= (SELECT rn - 15 FROM MyTable WHERE Year = @Year AND Month = @Month) 
    AND rn <= (SELECT rn + 15 FROM MyTable WHERE Year = @Year AND Month = @Month); 

Ich bin mir sicher, es gibt einen effizienteren Weg, es zu tun, aber dies scheint mir als der wartungsfreundlichste Weg, es zu tun. Es sollte sogar funktionieren, wenn Sie einen Wert in der Nähe des ersten oder letzten Datensatzes in der Tabelle auswählen.

Ich kann nicht sagen, ob Sie 31 Zeilen egal was wollen. An einem Punkt klingt es wie du, und an einem anderen Punkt klingt es wie du es nicht tust.

BEARBEITEN: Ok, also Sie wollen immer 31 Zeilen, wenn verfügbar.

Okay, versuchen Sie dies:

;WITH CTE AS (
    SELECT Month 
     ,Year 
     ,Value 
     ,ROW_NUMBER() OVER (ORDER BY Year, Month) rn 
    FROM MyTable 
    ), 
CTE_2 AS (
    SELECT TOP (31) Month 
     ,Year 
     ,Value 
    FROM CTE 
    ORDER BY ABS(rn - (SELECT rn FROM MyTable WHERE Year = @Year AND Month = @Month)) ASC 
    ) 
SELECT Month 
    ,Year 
    ,Value 
FROM CTE_2 
ORDER BY Year, Month; 

Grundsätzlich Sie berechnen, erhalten die Differenz von der Zielzeilennummer, die ersten 31 Reihen dort, und sie dann für die Ausgabe zurückgreifen.

+0

Dies ist nicht das, was ich brauche, wenn die abgefragte Zeile (@Year und @Month) die letzte ist, wird es nur 15 zusätzliche Datensätze davor zurückgeben. In diesem Fall muss ich 30 Datensätze zurückgeben. Grundsätzlich, wenn es weniger als 15 Zeilen nach der abgefragten Zeile gibt, muss ich zusätzliche Zeilen davor bekommen. – Coffka

+0

@ Coffka OK, das macht Sinn. Versuchen Sie meine aktualisierte Abfrage. –

+0

Sie erhalten bereits eine Zeilennummer in Ihrer Unterabfrage, die nicht dort ist. – Mihai

0

Check this out,

DECLARE @iPrevRows int 
DECLARE @iPostRows int 
DECLARE @Year int = 2016 
DECLARE @Month int = 2 

SELECT @iPrevRows= Count(*) 
FROM 
[GuestBook].[dbo].[tblTest] 
where (year < @Year) 
    or (year [email protected] and month < @Month) 

SELECT @iPostRows= count(*) from 
[GuestBook].[dbo].[tblTest] 
where (year > @Year) 
    or (year [email protected] and month > @Month) 

if (@iPrevRows > 15) 
    select @iPrevRows =15 

if (@iPostRows > 15) 
    select @iPostRows =15 

if (@iPrevRows < 15) 
    select @iPostRows = @iPostRows + ([email protected]) 
else if (@iPostRows < 15) 
    select @iPrevRows = @iPrevRows + ([email protected]) 

CREATE TABLE #tempValues 
(
Year int NOT NULL, 
Month int NOT NULL, 
Value float 
) 

insert into #tempValues 

SELECT top (@iPrevRows) Month, Year, Value 
from 
[GuestBook].[dbo].[tblTest] 
where (year < @Year) 
or (year [email protected] and month < @Month) 
order by 2 desc,1 desc 

insert into #tempValues 
SELECT Month, Year, Value 
from 
[GuestBook].[dbo].[tblTest] 
where  (year [email protected] and month = @Month) 

insert into #tempValues 
SELECT top (@iPostRows) Month, Year, Value 
from 
[GuestBook].[dbo].[tblTest] 
where (year > @Year) 
    or (year [email protected] and month > @Month) 
    order by 2 ,1 

select * from #tempValues 
order by 2,1 
0

Hier ist, was ich getan habe, scheint

select * from (
    select top(31) * from MyTable r 
    order by ABS(DATEDIFF(month, DATEFROMPARTS(r.Year, r.Month, 1), DATEFROMPARTS(@Year, @Month, 1)))) s 
order by Year, Month 
+0

Leider ist diese Abfrage aufgrund der Funktionen, die auf jede Zeile angewendet werden, nicht [SARGABLE] (https://en.wikipedia.org/wiki/Sargable), so dass die Leistung leidet, wenn die Tabelle wächst. – HABO

Verwandte Themen