Benutzer mit den meisten Antworten
Nur eine Zeile aus der rechten Join Tabelle

Frage
-
Guten Morgen,
hier erstmal meine Datenstruktur:
CREATE TABLE [dbo].[Test]( [Id] [int] IDENTITY(1,1) NOT NULL, [Name] [nvarchar](55) NOT NULL, [Beginn] [datetime] NOT NULL, [Ende] [datetime] NOT NULL ) ON [PRIMARY] GO SET IDENTITY_INSERT [dbo].[Test] ON GO INSERT [dbo].[Test] ([Id], [Name], [Beginn], [Ende]) VALUES (1, N'Montag', CAST(N'2018-03-26T00:00:00.000' AS DateTime), CAST(N'2018-03-27T00:00:00.000' AS DateTime)) GO INSERT [dbo].[Test] ([Id], [Name], [Beginn], [Ende]) VALUES (2, N'Dienstag', CAST(N'2018-03-27T00:00:00.000' AS DateTime), CAST(N'2018-03-28T00:00:00.000' AS DateTime)) GO INSERT [dbo].[Test] ([Id], [Name], [Beginn], [Ende]) VALUES (3, N'Mittwoch', CAST(N'2018-03-28T00:00:00.000' AS DateTime), CAST(N'2018-03-29T00:00:00.000' AS DateTime)) GO INSERT [dbo].[Test] ([Id], [Name], [Beginn], [Ende]) VALUES (4, N'Donnerstag', CAST(N'2018-03-29T00:00:00.000' AS DateTime), CAST(N'2018-03-30T00:00:00.000' AS DateTime)) GO INSERT [dbo].[Test] ([Id], [Name], [Beginn], [Ende]) VALUES (5, N'Freitag', CAST(N'2018-03-30T00:00:00.000' AS DateTime), CAST(N'2018-03-31T00:00:00.000' AS DateTime)) GO SET IDENTITY_INSERT [dbo].[Test] OFF
Hier mein Select:
Select T1.Name, T1.Beginn, T1.Ende, T2.Name as NameNaechster, T2.Beginn as BeginnNaechster, T2.Ende as EndeNaechster from Test T1 LEFT OUTER JOIN Test T2 ON T2.Beginn>T1.Ende WHERE T1.Name='Montag'
Ich möchte erreichen dass ich einen bestimmten Datensatz auswähle und zeitlich gesehen (Beginn > Ende) immer geneu den nächsten Datensatz auch erhalte. Existiert er nicht sollen die Felder NULL sein.
Mir gelingt die Einschränkung auf einen Datensatz nicht. Mit dem Aktuellen Select erhalte ich insgesamt drei Zeilen obwohl es nur eine sein dürfte.
Dass die Wochentage im Beispiel aufsteigend sind, ist nur ein konstuierter Zufall.
Kann mir jemand helfen?
Viele Grüße
Thorsten
Antworten
-
Hallo Eclere,
das kannst Du mit einem OUTER APPLY sehr schön realisieren:
SELECT L.Name, L.Beginn, L.Ende, N.* FROM dbo.Test AS L OUTER APPLY ( SELECT TOP (1) Name AS NameNaechster, Beginn AS BeginnNaechster, Ende AS EndeNaechster FROM dbo.Test WHERE Beginn > L.Ende ORDER BY Beginn ) AS N WHERE L.Name = 'Freitag'; GO
Mehr Details zu CROSS APPLY und OUTER APPLY hier!
https://www.mssqltips.com/sqlservertip/1958/sql-server-cross-apply-and-outer-apply/
Uwe Ricken (Blog | Twitter)
Microsoft Certiied Master - SQL Server 2008
Microsoft Certified Solution Master - CHARTER Data Platform
Microsoft Certified Solution Expert - Data Platform
db Berater GmbH
Microsoft SQL Server Blog (german only)- Als Antwort vorgeschlagen Ivan DragovMicrosoft contingent staff, Moderator Freitag, 30. März 2018 05:32
- Als Antwort markiert Ivan DragovMicrosoft contingent staff, Moderator Freitag, 6. April 2018 08:41
Alle Antworten
-
Hallo Thorsten,
wenn es immer nur ein Datensatz sein soll, reicht ein einfaches TOP 1 mit entsprechender Sortierung aus
Select TOP 1 T1.Name, T1.Beginn, T1.Ende, T2.Name as NameNaechster, T2.Beginn as BeginnNaechster, T2.Ende as EndeNaechster from #Test AS T1 LEFT OUTER JOIN #Test T2 ON T2.Beginn>T1.Ende WHERE T1.Name='Montag' ORDER BY T2.Beginn
Olaf Helper
[ Blog] [ Xing] [ MVP] -
Hallo nochmal,
das beste Ergebnis habe ich bisher mit CTE hinbekommen:
WITH cte1 (Name, Beginn,Ende) AS ( select Name, Beginn,Ende from Test where Name='Montag' ), cte2 (Name, Beginn,Ende) AS ( select top(1) Name, Beginn,Ende from Test order by Beginn ) SELECT * FROM cte2 CROSS JOIN cte1
Was mir noch fehlt ist die Enschränkung in cte2 das Beginn > cte1.Ende sein soll. Ich habe hier ein schlaues Buch, in dem steht dass man immer auf die vorherige CTE zugreifen kann. Also schreibe ich:
WITH cte1 (Name, Beginn,Ende) AS ( select Name, Beginn,Ende from Test where Name='Montag' ), cte2 (Name, Beginn,Ende) AS ( select top(1) Name, Beginn,Ende from Test WHERE Beginn>=cte1.Ende order by Beginn ) SELECT * FROM cte2 CROSS JOIN cte1
erhalte dann aber den Fehler:
Der mehrteilige Bezeichner "cte1.Ende" konnte nicht gebunden werden.
Falls jemand den entscheidenden Tipp hat...
Viele Grüße
Thorsten
-
Ein Zugriff auf die CTE-Tabellen ist nur mittels "from" möglich, da sie wie Tables/Views fungieren.
Also
with cte1 (......) as (....)
, cte2 (....) as (select * from cte1 ....)Dies hilft dir in deinem Fall leider auch nicht.
Du kannst hier ggf. mit einem skalaren Subselect arbeiten (kleinstes Ende, dass >= Begin ist):with cte1 (Name, Begin, Ende, B_Ende) as (
select Name, Begin, Ende
,(select min(Ende) from Test b where a.Begin >= b.Ende) as B_Ende
from Test a
where ...
)Select * from CTE1
left join Test B on B_Ende = B.Ende -
Hallo Eclere,
das kannst Du mit einem OUTER APPLY sehr schön realisieren:
SELECT L.Name, L.Beginn, L.Ende, N.* FROM dbo.Test AS L OUTER APPLY ( SELECT TOP (1) Name AS NameNaechster, Beginn AS BeginnNaechster, Ende AS EndeNaechster FROM dbo.Test WHERE Beginn > L.Ende ORDER BY Beginn ) AS N WHERE L.Name = 'Freitag'; GO
Mehr Details zu CROSS APPLY und OUTER APPLY hier!
https://www.mssqltips.com/sqlservertip/1958/sql-server-cross-apply-and-outer-apply/
Uwe Ricken (Blog | Twitter)
Microsoft Certiied Master - SQL Server 2008
Microsoft Certified Solution Master - CHARTER Data Platform
Microsoft Certified Solution Expert - Data Platform
db Berater GmbH
Microsoft SQL Server Blog (german only)- Als Antwort vorgeschlagen Ivan DragovMicrosoft contingent staff, Moderator Freitag, 30. März 2018 05:32
- Als Antwort markiert Ivan DragovMicrosoft contingent staff, Moderator Freitag, 6. April 2018 08:41
-
Hallo Zusammen,
die OUTER APPLY Lösung von Uwe funktioniert wunderbar - Danke wieder etwas gelernt!
Allerding denke ich, dass aufgrund der "überschneidenden" Daten diese Daten auf kurz vor Mitternacht stehen sollten oder halt die Bedingung (in diesem Fall)
WHERE Beginn >= L.Ende
lauten sollte.
Liebe Grüße Volker