Wie kann der Mindestwert am besten aus mehreren Spalten ausgewählt werden?

80

Gegeben die folgende Tabelle in SQL Server 2005:

ID   Col1   Col2   Col3
--   ----   ----   ----
1       3     34     76  
2      32    976     24
3       7    235      3
4     245      1    792

Was ist der beste Weg, um die Abfrage zu schreiben, die das folgende Ergebnis liefert (dh eine, die die letzte Spalte ergibt - eine Spalte, die die Miniumwerte von Col1, Col2 und Col3 für jede Zeile enthält )?

ID   Col1   Col2   Col3  TheMin
--   ----   ----   ----  ------
1       3     34     76       3
2      32    976     24      24
3       7    235      3       3
4     245      1    792       1

AKTUALISIEREN:

Zur Verdeutlichung (wie ich in den Kommentaren gesagt habe) wird die Datenbank im realen Szenario ordnungsgemäß normalisiert . Diese "Array" -Spalten befinden sich nicht in einer tatsächlichen Tabelle, sondern in einer Ergebnismenge, die in einem Bericht erforderlich ist. Die neue Anforderung besteht darin, dass der Bericht auch diese MinValue-Spalte benötigt. Ich kann die zugrunde liegende Ergebnismenge nicht ändern und habe daher bei T-SQL nach einer praktischen "Ausstiegskarte" gesucht.

Ich habe den unten erwähnten CASE-Ansatz ausprobiert und er funktioniert, obwohl er etwas umständlich ist. Es ist auch komplizierter als in den Antworten angegeben, da Sie die Tatsache berücksichtigen müssen, dass sich zwei Min-Werte in derselben Zeile befinden.

Wie auch immer, ich dachte, ich würde meine aktuelle Lösung veröffentlichen, die angesichts meiner Einschränkungen ziemlich gut funktioniert. Es verwendet den UNPIVOT-Operator:

with cte (ID, Col1, Col2, Col3)
as
(
    select ID, Col1, Col2, Col3
    from TestTable
)
select cte.ID, Col1, Col2, Col3, TheMin from cte
join
(
    select
        ID, min(Amount) as TheMin
    from 
        cte 
        UNPIVOT (Amount for AmountCol in (Col1, Col2, Col3)) as unpvt
    group by ID
) as minValues
on cte.ID = minValues.ID

Ich werde im Voraus sagen, dass ich nicht erwarte, dass dies die beste Leistung bietet, aber angesichts der Umstände (ich kann nicht alle Abfragen nur für die neue MinValue-Spaltenanforderung neu gestalten) ist es ein ziemlich eleganter Ausstieg aus dem Gefängnis Karte".

stucampbell
quelle
11
IMHO ist die UNPIVOT-Lösung des Autors den anderen Antworten überlegen.
Joe Harris
2
Ich finde, dass Nizams Lösung die schlankste Lösung ist, auch wenn ich eine Weile gebraucht habe, um sie zu verstehen. Schlank und sehr benutzerfreundlich.
Patrick Honorez

Antworten:

58

Es gibt wahrscheinlich viele Möglichkeiten, dies zu erreichen. Mein Vorschlag ist, Case / When zu verwenden. Mit 3 Spalten ist es nicht schlecht.

Select Id,
       Case When Col1 < Col2 And Col1 < Col3 Then Col1
            When Col2 < Col1 And Col2 < Col3 Then Col2 
            Else Col3
            End As TheMin
From   YourTableNameHere
George Mastros
quelle
6
Dies war mein erster Gedanke. Die eigentliche Abfrage benötigt jedoch 5 Spalten, und die Anzahl der Spalten kann zunehmen. Der CASE-Ansatz wird also etwas unhandlich. Aber es funktioniert.
Stucampbell
2
Wenn die Anzahl der Spalten zunehmen könnte, machen Sie es definitiv falsch - siehe meinen Beitrag (der Grund, warum Sie Ihr DB-Schema nicht so einrichten sollten :-).
Paxdiablo
2
Vielen Dank. Wie ich in einem anderen Kommentar erwähnt habe. Ich frage keine tatsächlichen Tabellen ab. Die Tabellen sind korrekt normalisiert. Diese Abfrage ist Teil einer besonders komplexen Abfrage und arbeitet an Zwischenergebnissen aus abgeleiteten Tabellen.
Stucampbell
2
Können Sie sie in diesem Fall anders ableiten, damit sie normal aussehen?
Kev
3
Ein Add-On zur Antwort von @Gmastros, als ich auf das Problem stieß, dass einige der Cols übereinstimmende Daten hatten, sodass ich das = -Zeichen hinzufügen musste. Meine Daten hatten auch das Potenzial für null, daher musste ich die Anweisung oder hinzufügen, um dies zu berücksichtigen. Es gibt vielleicht einen einfacheren Weg, dies zu tun, aber ich habe in den letzten 6 Monaten, die ich gesucht habe, keinen gefunden. Vielen Dank an alle Beteiligten. Wählen Sie Id, CaseWhen (Col1 <= Col2 ODER Col2 ist null) und (Col1 <= Col3 ODER Col3 ist null) Dann Col1 Wann (Col2 <= Col1 ODER Col1 ist null) Und (Col2 <= Col3 ODER Col3 ist null) Dann Col2 Else Col3 End As TheMin von YourTableNameHere
Chad Portman
53

Verwenden von CROSS APPLY:

SELECT ID, Col1, Col2, Col3, MinValue
FROM YourTable
CROSS APPLY (SELECT MIN(d) AS MinValue FROM (VALUES (Col1), (Col2), (Col3)) AS a(d)) A

SQL Fiddle

Nizam
quelle
Sieht interessant aus, aber ich kann das nicht zum Laufen bringen. Könnten Sie vielleicht ein bisschen explizit? Danke
Patrick Honorez
2
@iDevlop Ich habe die SQL-Geige in meine Antwort eingefügt
Nizam
Was ich nicht wusste, war die Skalarfunktion. Es scheint, dass Ihre Antwort auch ohne die funktioniert cross apply. Fügt es Mehrwert / Leistung hinzu? stackoverflow.com/a/14712024/78522
Patrick Honorez
@iDevlop Wenn es keine Leistung liefert, erhöht es die Lesbarkeit. Zum Beispiel könnte ich so etwas verwenden where MinValue > 10, auf das ich nicht verzichten könnteCROSS APPLY
Nizam
2
In der Tat hatte ich in der Zwischenzeit die Gelegenheit, den Nutzen der "Wiederverwendbarkeit" zu verstehen. Vielen Dank. Ich habe heute 2 Dinge gelernt
;-)
25
SELECT ID, Col1, Col2, Col3, 
    (SELECT MIN(Col) FROM (VALUES (Col1), (Col2), (Col3)) AS X(Col)) AS TheMin
FROM Table
dsz
quelle
1
Danke für den Fang. Ich hatte diesen Tag verpasst. Ich weiß es eigentlich nicht und kann es auch nicht testen. Wird in Zukunft sorgfältiger bei der Überprüfung von Tags sein.
dsz
3
Zweifellos die elegantere Lösung - nicht sicher, warum es nicht mehr positive Stimmen gibt.
Jwolf
Für Inline-Max / Min-Berechnungen ist dies bei weitem der beste Weg, dies zu tun
Saxman
15

Verwenden Sie unter MySQL Folgendes:

select least(col1, col2, col3) FROM yourtable
user3493139
quelle
Könnte keine SQL-Anweisung sein.
Tino Jose Thannippara
4
aber in einigen Fällen ist es. Für diese ist dies eine wunderbare Antwort
Kirby
1
Verfügbar in Postgres seit 8.1: postgresql.org/docs/8.1/functions-conditional.html#AEN12704
swrobel
1
Diese nicht standardmäßige SQL-Erweiterung wird von nahezu jeder Datenbank außer Microsoft SQL Server unterstützt.
Mikko Rantalainen
Nur zu Ihrer Information, es funktioniert auch in Snowflake
Ramil Gataullin
10

Sie können den "Brute Force" -Ansatz mit einer Wendung verwenden:

SELECT CASE
    WHEN Col1 <= Col2 AND Col1 <= Col3 THEN Col1
    WHEN                  Col2 <= Col3 THEN Col2
    ELSE                                    Col3
END AS [Min Value] FROM [Your Table]

Wenn die erste Bedingung fehlschlägt, wird garantiert, dass Col1 nicht der kleinste Wert ist. Sie können ihn daher aus den übrigen Bedingungen entfernen. Ebenso für nachfolgende Bedingungen. Für fünf Spalten lautet Ihre Abfrage:

SELECT CASE
    WHEN Col1 <= Col2 AND Col1 <= Col3 AND Col1 <= Col4 AND Col1 <= Col5 THEN Col1
    WHEN                  Col2 <= Col3 AND Col2 <= Col4 AND Col2 <= Col5 THEN Col2
    WHEN                                   Col3 <= Col4 AND Col3 <= Col5 THEN Col3
    WHEN                                                    Col4 <= Col5 THEN Col4
    ELSE                                                                      Col5
END AS [Min Value] FROM [Your Table]

Beachten Sie, dass bei einem Gleichstand zwischen zwei oder mehr Spalten <=sichergestellt wird, dass die CASEAnweisung so früh wie möglich beendet wird.

Salman A.
quelle
2
Verwenden Sie <=stattdessen, andernfalls wird der letzte übereinstimmende Mindestwert anstelle des ersten verwendet.
chezy525
6

Wenn die Spalten Ganzzahlen wie in Ihrem Beispiel wären, würde ich eine Funktion erstellen:

create function f_min_int(@a as int, @b as int) 
returns int
as
begin
    return case when @a < @b then @a else coalesce(@b,@a) end
end

dann, wenn ich es benutzen muss, würde ich tun:

select col1, col2, col3, dbo.f_min_int(dbo.f_min_int(col1,col2),col3)

Wenn Sie 5 Spalten haben, wird das oben genannte

select col1, col2, col3, col4, col5,
dbo.f_min_int(dbo.f_min_int(dbo.f_min_int(dbo.f_min_int(col1,col2),col3),col4),col5)
Georgios
quelle
4
Angesichts der lächerlich schlechten Leistung von Skalarfunktionen in MSSQL fühle ich mich verpflichtet, von diesem Ansatz abzuraten. Wenn Sie diesen Weg gehen möchten, schreiben Sie mindestens eine Funktion, die alle 5 Spalten gleichzeitig als Parameter verwendet. Es wird immer noch schlecht sein, aber zumindest ein bisschen weniger schlecht = /
deroby
Rekursion verringert die Leistung. Aber es wird die Anforderung erfüllen.
Tino Jose Thannippara
6

Der beste Weg, dies zu tun, ist wahrscheinlich, es nicht zu tun - es ist seltsam, dass die Leute darauf bestehen, ihre Daten so zu speichern, dass SQL "Gymnastik" erforderlich ist, um aussagekräftige Informationen zu extrahieren, wenn es weitaus einfachere Möglichkeiten gibt, das gewünschte Ergebnis zu erzielen, wenn Sie dies nur tun strukturiere dein Schema etwas besser :-)

Der richtige Weg, dies zu tun, ist meiner Meinung nach die folgende Tabelle:

ID    Col    Val
--    ---    ---
 1      1      3
 1      2     34
 1      3     76

 2      1     32
 2      2    976
 2      3     24

 3      1      7
 3      2    235
 3      3      3

 4      1    245
 4      2      1
 4      3    792

mit ID/Colals Primärschlüssel (und möglicherweise Colals zusätzlicher Schlüssel, abhängig von Ihren Anforderungen). Dann wird Ihre Abfrage einfach select min(val) from tblund Sie können die einzelnen "alten Spalten" weiterhin separat behandeln, indem Sie sie where col = 2in Ihren anderen Abfragen verwenden. Dies ermöglicht auch eine einfache Erweiterung, falls die Anzahl der "alten Spalten" zunimmt.

Dies macht Ihre Anfragen so viel einfacher. Die allgemeine Richtlinie, die ich normalerweise verwende, lautet: Wenn Sie jemals etwas haben, das wie ein Array in einer Datenbankzeile aussieht, machen Sie wahrscheinlich etwas falsch und sollten über eine Umstrukturierung der Daten nachdenken.


Wenn Sie diese Spalten jedoch aus irgendeinem Grund nicht ändern können, würde ich empfehlen, Trigger zum Einfügen und Aktualisieren zu verwenden und eine weitere Spalte hinzuzufügen , für die diese Trigger das Minimum festgelegt haben Col1/2/3. Dadurch werden die "Kosten" des Vorgangs von der Auswahl zu dem Update / Insert verschoben, zu dem sie gehören. Die meisten Datenbanktabellen werden meiner Erfahrung nach weitaus häufiger gelesen als geschrieben, sodass die Kosten für das Schreiben im Laufe der Zeit tendenziell effizienter sind.

Mit anderen Worten ändert sich das Minimum für eine Zeile nur dann , wenn eine der anderen Spalten zu ändern, so dass die , wenn Sie es werden die Berechnung sollte, nicht jedes Mal , wenn Sie wählen (was , wenn die Daten verschwendet wird , ist nicht zu ändern). Sie würden dann mit einem Tisch wie folgt enden:

ID   Col1   Col2   Col3   MinVal
--   ----   ----   ----   ------
 1      3     34     76        3
 2     32    976     24       24
 3      7    235      3        3
 4    245      1    792        1

Jede andere Option, die zu einem bestimmten selectZeitpunkt Entscheidungen treffen muss, ist in Bezug auf die Leistung normalerweise eine schlechte Idee, da sich die Daten nur beim Einfügen / Aktualisieren ändern. Das Hinzufügen einer weiteren Spalte nimmt mehr Platz in der Datenbank ein und ist für die Einfügungen und etwas langsamer Aktualisierungen können jedoch für die Auswahl viel schneller sein - der bevorzugte Ansatz sollte von Ihren Prioritäten dort abhängen, aber wie bereits erwähnt, werden die meisten Tabellen weitaus häufiger gelesen als geschrieben.

paxdiablo
quelle
18
Äh. Danke für die Schande. Die reale Datenbank ist ordnungsgemäß normalisiert. Dies war ein einfaches Beispiel. Die eigentliche Abfrage ist kompliziert und die 5 Spalten, an denen ich interessiert bin, sind Zwischenergebnisse aus abgeleiteten Tabellen.
Stucampbell
3
Die Schande steht leider noch. Das Erstellen von Zwischentabellen des von Ihnen vorgeschlagenen Formulars ist genauso problematisch wie das Erstellen solcher permanenten Tabellen. Dies wird durch die Tatsache belegt, dass Sie das ausführen müssen, was ich als SQL-Gymnastik bezeichne, um das gewünschte Ergebnis zu erzielen.
Paxdiablo
Wenn es echte Gründe gibt, das 'Array' in einer einzelnen Zeile zu benötigen, können Sie uns gerne aufklären, aber die Verwendung des Minimalwerts ist nicht einer davon.
Paxdiablo
2
+1 für den Trigger-Vorschlag, um die ursprüngliche (falls fehlerhafte) Tabellenstruktur beizubehalten.
Scott Ferguson
Was ist, wenn Sie es mit einer Hierarchietabelle zu tun haben, die selbst mit dieser Tabelle verbunden ist?
Nathan Tregillus
5

Sie können dies auch mit einer Gewerkschaftsabfrage tun. Wenn die Anzahl der Spalten zunimmt, müssten Sie die Abfrage ändern, aber zumindest wäre dies eine einfache Änderung.

Select T.Id, T.Col1, T.Col2, T.Col3, A.TheMin
From   YourTable T
       Inner Join (
         Select A.Id, Min(A.Col1) As TheMin
         From   (
                Select Id, Col1
                From   YourTable

                Union All

                Select Id, Col2
                From   YourTable

                Union All

                Select Id, Col3
                From   YourTable
                ) As A
         Group By A.Id
       ) As A
       On T.Id = A.Id
George Mastros
quelle
2
Dies funktioniert, aber die Leistung nimmt ab, wenn die Zeilenanzahl steigt.
Tomalak
1
Vielen Dank. Ja das funktioniert. Wie Tomalak sagt, wäre dies in meiner Realword-Abfrage für die Leistung ziemlich unangenehm. Aber +1 für Mühe. :)
stucampbell
3

Das ist rohe Gewalt, funktioniert aber

 select case when col1 <= col2 and col1 <= col3 then col1
           case when col2 <= col1 and col2 <= col3 then col2
           case when col3 <= col1 and col3 <= col2 then col3
    as 'TheMin'
           end

from Table T

... weil min () nur für eine Spalte und nicht für mehrere Spalten funktioniert.

Lernen
quelle
2

Sowohl diese Frage als auch diese Frage versuchen dies zu beantworten.

Die Zusammenfassung ist, dass Oracle eine eingebaute Funktion dafür hat. Mit SQL Server können Sie entweder eine benutzerdefinierte Funktion definieren oder case-Anweisungen verwenden.

Sam Safran
quelle
2

Für mehrere Spalten ist es am besten, eine CASE-Anweisung zu verwenden. Für zwei numerische Spalten i und j können Sie jedoch einfache Berechnungen verwenden:

min (i, j) = (i + j) / 2 - abs (ij) / 2

Diese Formel kann verwendet werden, um den Mindestwert mehrerer Spalten zu erhalten, aber die wirklich unordentliche Zeit nach 2, min (i, j, k) wäre min (i, min (j, k)).

Crowley
quelle
1

Wenn Sie in der Lage sind, eine gespeicherte Prozedur zu erstellen, kann dies eine Reihe von Werten erfordern, und Sie können dies einfach aufrufen.

Kev
quelle
Oracle hat eine Funktion namens LEAST (), die genau das tut, was Sie wollen.
Kev
Vielen Dank, dass Sie das reiben :) Ich kann nicht glauben, dass SQL Server kein Äquivalent hat!
Stucampbell
Ich wollte sogar sagen: "Hey, mein Lieblings-Pgsql hat es auch nicht", aber es tut es tatsächlich. ;) Die Funktion selbst wäre allerdings nicht schwer zu schreiben.
Kev
Oh, außer dass T-SQL nicht einmal Array-Unterstützung hat (???) Nun, ich denke, Sie könnten eine Fünf-Parameter-Funktion haben und wenn Sie mehr brauchen, erweitern Sie sie einfach ...
Kev
1
select *,
case when column1 < columnl2 And column1 < column3 then column1
when columnl2 < column1 And columnl2 < column3 then columnl2
else column3
end As minValue
from   tbl_example
Phil Corcoran
quelle
1
Dies ist ein Duplikat der Antwort von G Mastros. Wenn Sie sich also fragen sollten: Ich denke, das ist der Grund, warum die Abstimmung abstimmt.
Tomalak
1

Eine kleine Wendung bei der Gewerkschaftsabfrage:

DECLARE @Foo TABLE (ID INT, Col1 INT, Col2 INT, Col3 INT)

INSERT @Foo (ID, Col1, Col2, Col3)
VALUES
(1, 3, 34, 76),
(2, 32, 976, 24),
(3, 7, 235, 3),
(4, 245, 1, 792)

SELECT
    ID,
    Col1,
    Col2,
    Col3,
    (
        SELECT MIN(T.Col)
        FROM
        (
            SELECT Foo.Col1 AS Col UNION ALL
            SELECT Foo.Col2 AS Col UNION ALL
            SELECT Foo.Col3 AS Col 
        ) AS T
    ) AS TheMin
FROM
    @Foo AS Foo
Neunauge
quelle
1

Wenn Sie SQL 2005 verwenden, können Sie Folgendes tun:

;WITH    res
          AS ( SELECT   t.YourID ,
                        CAST(( SELECT   Col1 AS c01 ,
                                        Col2 AS c02 ,
                                        Col3 AS c03 ,
                                        Col4 AS c04 ,
                                        Col5 AS c05
                               FROM     YourTable AS cols
                               WHERE    YourID = t.YourID
                             FOR
                               XML AUTO ,
                                   ELEMENTS
                             ) AS XML) AS colslist
               FROM     YourTable AS t
             )
    SELECT  YourID ,
            colslist.query('for $c in //cols return min(data($c/*))').value('.',
                                            'real') AS YourMin ,
            colslist.query('for $c in //cols return avg(data($c/*))').value('.',
                                            'real') AS YourAvg ,
            colslist.query('for $c in //cols return max(data($c/*))').value('.',
                                            'real') AS YourMax
    FROM    res

Auf diese Weise verlieren Sie sich nicht in so vielen Operatoren :)

Dies könnte jedoch langsamer sein als die andere Wahl.

Es ist Ihre Wahl...

Leoinfo
quelle
Nun, wie gesagt, dies könnte langsam sein, aber wenn Sie zu viele Spalten haben (offensichtlich aufgrund eines wirklich schlechten DB-Designs!), Könnte es sich lohnen, dies zu verwenden (zumindest für AVG). Du hast mir keinen Hinweis gegeben, ob es eine gute heilige Kuh oder eine schlechte ist :) Vielleicht solltest du die Auf- / Ab-Abstimmung verwenden, um mich herauszufinden.
Leoinfo
Es war nicht wirklich gut oder schlecht;). Ich bin kein Datenbankexperte, also habe ich nur "Heilige Kuh" gesagt, weil die Frage eine triviale Antwort zu haben schien. Ich denke, es ist gut, da Sie es geschafft haben, eine flexible, erweiterbare Lösung für das Problem bereitzustellen!
Dreamlax
1

Unten verwende ich eine temporäre Tabelle, um das Minimum von mehreren Daten zu erhalten. Die erste temporäre Tabelle fragt mehrere verknüpfte Tabellen ab, um verschiedene Daten (sowie andere Werte für die Abfrage) abzurufen. Die zweite temporäre Tabelle ruft dann die verschiedenen Spalten und das Mindestdatum mit so vielen Durchläufen ab, wie es Datumsspalten gibt.

Dies ähnelt im Wesentlichen der Gewerkschaftsabfrage. Es ist dieselbe Anzahl von Durchläufen erforderlich, kann jedoch effizienter sein (basierend auf Erfahrung, müsste jedoch getestet werden). Effizienz war in diesem Fall kein Problem (8.000 Datensätze). Man könnte indexieren etc.

--==================== this gets minimums and global min
if object_id('tempdb..#temp1') is not null
    drop table #temp1
if object_id('tempdb..#temp2') is not null
    drop table #temp2

select r.recordid ,  r.ReferenceNumber, i.InventionTitle, RecordDate, i.ReceivedDate
, min(fi.uploaddate) [Min File Upload], min(fi.CorrespondenceDate) [Min File Correspondence]
into #temp1
from record r 
join Invention i on i.inventionid = r.recordid
left join LnkRecordFile lrf on lrf.recordid = r.recordid
left join fileinformation fi on fi.fileid = lrf.fileid
where r.recorddate > '2015-05-26'
 group by  r.recordid, recorddate, i.ReceivedDate,
 r.ReferenceNumber, i.InventionTitle



select recordid, recorddate [min date]
into #temp2
from #temp1

update #temp2
set [min date] = ReceivedDate 
from #temp1 t1 join #temp2 t2 on t1.recordid = t2.recordid
where t1.ReceivedDate < [min date] and  t1.ReceivedDate > '2001-01-01'

update #temp2 
set [min date] = t1.[Min File Upload]
from #temp1 t1 join #temp2 t2 on t1.recordid = t2.recordid
where t1.[Min File Upload] < [min date] and  t1.[Min File Upload] > '2001-01-01'

update #temp2
set [min date] = t1.[Min File Correspondence]
from #temp1 t1 join #temp2 t2 on t1.recordid = t2.recordid
where t1.[Min File Correspondence] < [min date] and t1.[Min File Correspondence] > '2001-01-01'


select t1.*, t2.[min date] [LOWEST DATE]
from #temp1 t1 join #temp2 t2 on t1.recordid = t2.recordid
order by t1.recordid
user3438020
quelle
1
SELECT [ID],
            (
                SELECT MIN([value].[MinValue])
                FROM
                (
                    VALUES
                        ([Col1]),
                        ([Col1]),
                        ([Col2]),
                        ([Col3])
                ) AS [value] ([MinValue])
           ) AS [MinValue]
FROM Table;
Tino Jose Thannippara
quelle
0

Wenn Sie wissen, nach welchen Werten Sie suchen, normalerweise nach einem Statuscode, kann Folgendes hilfreich sein:

select case when 0 in (PAGE1STATUS ,PAGE2STATUS ,PAGE3STATUS,
PAGE4STATUS,PAGE5STATUS ,PAGE6STATUS) then 0 else 1 end
FROM CUSTOMERS_FORMS
Israel Margulies
quelle
0

Ich weiß, dass diese Frage alt ist, aber ich brauchte die Antwort immer noch und war mit anderen Antworten nicht zufrieden, also musste ich meine eigene entwickeln, was eine Wendung in der Antwort von @ paxdiablo darstellt .


Ich kam aus dem Land von SAP ASE 16.0 und brauchte nur einen Blick auf Statistiken bestimmter Daten, die meiner Meinung nach in verschiedenen Spalten einer einzelnen Zeile gültig gespeichert sind (sie repräsentieren unterschiedliche Zeiten - als die Ankunft von etwas geplant war, was erwartet wurde, wann Die Aktion begann und schließlich, was war die tatsächliche Zeit). Daher hatte ich Spalten in die Zeilen der temporären Tabelle transponiert und meine Abfrage darüber wie gewohnt durchgeführt.

NB Nicht die Einheitslösung!

CREATE TABLE #tempTable (ID int, columnName varchar(20), dataValue int)

INSERT INTO #tempTable 
  SELECT ID, 'Col1', Col1
    FROM sourceTable
   WHERE Col1 IS NOT NULL
INSERT INTO #tempTable 
  SELECT ID, 'Col2', Col2
    FROM sourceTable
   WHERE Col2 IS NOT NULL
INSERT INTO #tempTable 
  SELECT ID, 'Col3', Col3
    FROM sourceTable
   WHERE Col3 IS NOT NULL

SELECT ID
     , min(dataValue) AS 'Min'
     , max(dataValue) AS 'Max'
     , max(dataValue) - min(dataValue) AS 'Diff' 
  FROM #tempTable 
  GROUP BY ID

Dies dauerte bei einem Quellensatz von 630000 Zeilen etwa 30 Sekunden und verwendete nur Indexdaten. Dies ist also nicht die Sache, die in einem zeitkritischen Prozess ausgeführt werden muss, sondern beispielsweise für eine einmalige Dateninspektion oder einen Tagesabschlussbericht gut (aber überprüfen Sie dies bitte mit Ihren Kollegen oder Vorgesetzten!). Hauptbonus dieses Stils für mich dass ich problemlos mehr / weniger Spalten verwenden und die Gruppierung, Filterung usw. ändern konnte, insbesondere nachdem die Daten kopiert wurden.

Die zusätzlichen Daten ( columnName, maxes, ...) sollten mir bei meiner Suche helfen, sodass Sie sie möglicherweise nicht benötigen. Ich habe sie hier gelassen, um vielleicht ein paar Ideen zu wecken :-).

Rao
quelle