2017-01-01 4 views
0

Die Tabelle tEmplHistory enthält chronologische Datensätze für Mitarbeiter. Jeder Datensatz hat ein Startdatum, das angibt, wann sich der Status für diesen Mitarbeiter ändert. Ich muss alle Aufzeichnungen für alle Mitarbeiter herausziehen, die einem gegebenen Datum am nächsten sind, aber nicht überschreiten. Der Datensatz für jeden Mitarbeiter wird derjenige sein, der unmittelbar vor diesem bestimmten Datum für diesen Mitarbeiter liegt. In der Ausgabe brauche ich die EmplHistoryID, das ist alles. Das, wo ich bin stecken:Diese Abfrage kann nicht richtig gruppiert werden

This is where I'm stuck Hier ist die Tabelle:

USE foo 
GO 

/****** Object: Table [dbo].[tEmplHistory] Script Date: 1/1/2017 6:12:54 PM ******/ 
SET ANSI_NULLS ON 
GO 

SET QUOTED_IDENTIFIER ON 
GO 

CREATE TABLE [dbo].[tEmplHistory](
    [EmplHistoryID] [int] IDENTITY(1,1) NOT NULL, 
    [StartDate] [datetime] NOT NULL, 
    [EmplStatusID] [int] NOT NULL, 
    [Comment] [nvarchar](max) NULL, 
    [DateStamp] [datetime] NOT NULL, 
    [EmplID] [int] NOT NULL, 
CONSTRAINT [PK_tEmplHistory] PRIMARY KEY CLUSTERED 
(
    [EmplHistoryID] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] 

GO 

Hier einige Daten:

INSERT 
    [dbo].[tEmplHistory] 
    ([EmplHistoryID], [StartDate], [EmplStatusID], [Comment], [DateStamp], [EmplID]) 
VALUES 
    (9375, CAST(0x0000A6EE0104A007 AS DateTime), 1, NULL, CAST(0x0000A6EE0104A007 AS DateTime), 2768), 
    (9376, CAST(0x0000A58000000000 AS DateTime), 1, NULL, CAST(0x0000A6EE010B2D97 AS DateTime), 2768), 
    (9377, CAST(0x0000A43100000000 AS DateTime), 1, NULL, CAST(0x0000A6EE010B481D AS DateTime), 2768), 
    (9378, CAST(0x0000A58100000000 AS DateTime), 1, NULL, CAST(0x0000A6EE010B591F AS DateTime), 2768), 
    (9379, CAST(0x0000A57F00000000 AS DateTime), 1, NULL, CAST(0x0000A6EE010B6F5C AS DateTime), 2768), 
    (9380, CAST(0x0000A57E00000000 AS DateTime), 1, NULL, CAST(0x0000A6EE010B7AB7 AS DateTime), 2768), 
    (9381, CAST(0x0000A58100000000 AS DateTime), 1, NULL, CAST(0x0000A6EE010B9343 AS DateTime), 2768), 
    (9382, CAST(0x0000A58200000000 AS DateTime), 2, NULL, CAST(0x0000A6EE01188D3E AS DateTime), 2767), 
    (9383, CAST(0x0000A57F00000000 AS DateTime), 2, NULL, CAST(0x0000A6EE011903FF AS DateTime), 2767), 
    (9384, CAST(0x0000A57E00000000 AS DateTime), 2, NULL, CAST(0x0000A6EE01194FF5 AS DateTime), 2767), 
    (9385, CAST(0x0000A58100000000 AS DateTime), 1, NULL, CAST(0x0000A6EE012780A6 AS DateTime), 2), 
    (9386, CAST(0x0000A58000000000 AS DateTime), 2, NULL, CAST(0x0000A6EE01278D59 AS DateTime), 2), 
    (9387, CAST(0x0000A57F00000000 AS DateTime), 3, NULL, CAST(0x0000A6EE0127A45A AS DateTime), 2) 

    SET IDENTITY_INSERT [dbo].[tEmplHistory] OFF 
    GO 

Für diese Beispieldaten I drei EmplHistoryID Werte brauchen:

9386 for EmplID = 2 
9383 for EmplID = 2767 
9376 for EmplID 2768 
+1

Ich empfehle die Abfrage von Hand anstelle des Abfrage-Designers - der Designer ist nicht aussagekräftig genug für etwas mehr als triviale Abfragen. – Dai

+0

Wo ist das "angegebene Datum", das Sie mit dem Startdatum vergleichen möchten? Ich sehe nicht, dass dies in Ihrer Tabelle enthalten ist. Soll ich also von einem Variablenparameter ausgehen, den Sie jedes Mal weitergeben möchten, wenn Sie diese Abfrage erstellen? – Edward

+0

Haben Sie einen "Angestelltentisch"? –

Antwort

0

Ich brauche alle Datensätze für alle Mitarbeiter, die einem bestimmten Datum am nächsten sind, aber nicht überschreiten, herauszuziehen.

Ihre Frage wird durch die verschleierten Daten in Ihren Beispieldaten schwieriger zu beantworten. In 20 Jahren T-SQL-Arbeit habe ich zum ersten Mal Binärwerte gesehen, die explizit in datetime konvertiert wurden. Normalerweise werden Literalwerte als Strings angegeben.

Die grundlegende Form Ihrer Abfrage ist jedoch nicht kompliziert. Sie wollen alle Aufzeichnungen vor einem Zeitpunkt bestimmen, nicht nur eine, so

select * from tEmplHistory where StartDate < '1/1/1990' 

oder was auch immer Datum, das Sie möchten angeben.

Aber vielleicht meinst du das nicht? Vielleicht meinst du die einzelne Zeile für jeden Mitarbeiter vor und einem Datum sicher? Dafür wollen Sie eine korrelierte Unterabfrage:

select * from tEmplHistory as H where exists (
    select 1 from tEmplHistory 
    where EmplHistoryID = H.EmplHistoryID 
    and StartDate < '1/1/1990' 
    group by EmplHistoryID 
    having max(StartDate) = H.StartDate 
) 

Die Unterabfrage findet das letzte Startdatum vor dem angegebenen Datum für jeden EmplHistoryID. Dieses Datum und die EmplHistoryID werden mit den Zeilen in der äußeren Tabelle verknüpft (die in diesem Fall dieselbe Tabelle ist).

+0

Ihr Rindfleisch ist mit SSMS. Es erzeugte das Skript. – nicomp

0

Für jeden Mitarbeiter möchten Sie den neuesten Datensatz vor einem bestimmten Datum. So können Sie Datensätze auswählen vor diesem Datum Rang Ihrer Datensätze pro Mitarbeiter nach Datum und halten Sie die neueste:

select emplid, emplhistoryid 
from 
(
    select 
    emplid, 
    emplhistoryid, 
    row_number() over(partition by emplid order by datestamp desc) as rn 
    from templhistory eh 
    where datestamp <= '20161231' 
) ranked 
where rn = 1; 
0

Wenn wir die Mitarbeiter, deren Status geändert, bevor 2016.01.01 die folgenden funktionieren würde, ziehen wollen.

SELECT EMPLHISTORYID ,EMPID FROM 
(
    SELECT EMPLHISTORYID,[EmplID] AS EMPID, 
    STARTDATE,RANK() OVER (PARTITION BY [EmplID] ORDER BY StarttDate Desc) as RNK 
FROM [dbo].[tEmplHistory] 
WHERE startDATE <='2016-01-01 00:00:00' 
)A 
WHERE A.RNK=1 
Verwandte Themen