Avatar billede simsen Mester
08. december 2011 - 13:14 Der er 15 kommentarer og
1 løsning

spørge på tid i en where clause

Hej,

Jeg har følgende 3 tabeller med felter:

Employees
...employeeId (nvarchar(50))
...employeeName (nvarchar(250))

WorkingHours
....startHours (int)
....startMinutes (int)

TimeStamps
....startDate (datetime)

Jeg har nu brug for at kunne trække alle de rækker ud, hvor startDates tid er større end  startHours + startMinutes (som er tid delt op i to felter)....

Det jeg har indtil nu er:

SELECT    dbo.Employees.employeeId, dbo.Employees.employeeName, dbo.Employees.employeeGroupId, dbo.Employees.isActive, dbo.WorkingHours.startHours,
                      dbo.WorkingHours.startMinutes, dbo.TimeStamps.startDate, dbo.TimeStamps.regStartDate
FROM        dbo.Employees LEFT OUTER JOIN
                      dbo.TimeStamps ON dbo.Employees.employeeId = dbo.TimeStamps.employeeId LEFT OUTER JOIN
                      dbo.WorkingHours ON dbo.Employees.employeeId = dbo.WorkingHours.employeeId
WHERE    (dbo.Employees.isActive = 1) AND (CONVERT(VARCHAR(10), dbo.TimeStamps.startDate, 120) >= '2011-11-22') AND (CONVERT(VARCHAR(10),
                      dbo.TimeStamps.startDate, 120) <= '2011-12-08')

Her får jeg korrekt 2 rækker ud. Nu er det så jeg også vil spørge i min where clause på om startDate's tid er større end startHours + startMinutes (sat sammen som tid).

De to rækker jeg får ud nu (har filtreret det urelevante fra):
Navn startHours startMinutes startDate
Hans Hansen 8 0 22-11-2011 08:00:00
Hans Hansen 8 0 08-12-2011 12:27:31

Det vil sige efter næste filtrering (som er den jeg skal have hjælp til) skal der kun være en....nemlig
Hans Hansen 8 0 08-12-2011 12:27:31
Da 12:27 er større en 08:00

Nogen der kan fortælle mig hvordan?

mvh
simsen :-)
Avatar billede Syska Mester
08. december 2011 - 15:11 #1
Dvs du til tage en DateTime og lægge Time til? Korrekt forstået?
Avatar billede simsen Mester
08. december 2011 - 17:39 #2
Nej

Jeg har en datetime = startDate
Jeg har så to int felter = startHours og startMinutes

nu vil jeg så (jeg er fuldstændig ligeglad med selve datoen) - have at den går alle rækker igennem hvor startDate er og så se på selve tiden for startDate er den større end startHours + startMinutes (startHours og startMinutes skal jo så på en eller anden måde lægges sammen som en time/minutfelt)....

Det jeg ville gøre i c# var at hente datoen (og kun datoen - ikke tiden) ud fra startDate - for hver enkelt række - smide den i en streng - tilføje startHours og startMinutes - og så convertere den til en dato og så lave en timespan på startDate og den konverterede dato - og altså gøre dette for hver række - hvis startDate så var større smide dem i en ny tabel og så bruge den nye tabel.....

Men aner så ikke hvordan man gør i SQL :-)

Og forklaring: Det drejer sig om at en medarbejder får angivet hvornår møde tidspunkt er - her i to int felter startHours (= 08) og startMinutes (=30).... Nu skal han så hver dag "stemple" ind - det gør han med en startDate (dato og klokkeslet)...Nu er det så en slemmer slemmer chef - han vil kontrollere om medarbejderen også møder som han skal - gør han ikke vil han have en liste med de medarbejdere, der ikke gør.... Og dertil skal jeg jo så gemmemgå samtlige rækker for indstemplingen og tjekke op med mødetidspunktet. Håber det giver lidt mere mening - ellers sig til :-)
Avatar billede Syska Mester
08. december 2011 - 20:36 #3
DECLARE @Min INT = 10;
DECLARE @Hour INT = 10;
DECLARE @Date DATETIME = '2011-12-14 20:20:20'

SELECT DATEADD(MI, @Hour * 60 + @Min, CAST(CAST(@Date AS Date) AS DATETIME))

Håber du selv kan smide det ind i din WHERE clause.
Avatar billede simsen Mester
09. december 2011 - 08:58 #4
Du er som vanligt en snut.... Smid et svar og tak for hjælpen :-)

Godt nok bruger jeg ikke 2008 og har dermed ikke Date formattet - men kunne se ideen og bygger nu en streng op og converterer den til en date:

DECLARE @Min INT
DECLARE @Hour INT
DECLARE @Date DATETIME

SET @Min = 5
Set @Hour = 10
Set @Date = '2011-12-14 20:20:20'

--SELECT DATEADD(MI, @Hour * 60 + @Min, CAST(CAST(@Date AS DATETIME) AS DATETIME)) AS newDate
SELECT (CONVERT(DATETIME, (CONVERT(VARCHAR(10), @Date, 120)) + ' ' + (CONVERT(VARCHAR(2), @Hour)) + ':' + (CONVERT(VARCHAR(2), @Min)) + ':00')) AS newDate

Så min endelige løsning kom til at se sådan her ud:

DROP TABLE #tempTable

SELECT    dbo.Employees.employeeId, dbo.Employees.employeeName, dbo.Employees.employeeGroupId, dbo.Employees.isActive, dbo.WorkingHours.startHours,
                      dbo.WorkingHours.startMinutes, dbo.TimeStamps.startDate, dbo.TimeStamps.regStartDate, dbo.TimeStamps.timeStampId, CONVERT(DATETIME,
                      CONVERT(VARCHAR(10), dbo.TimeStamps.startDate, 120) + ' ' + CONVERT(VARCHAR(2), dbo.WorkingHours.startHours) + ':' + CONVERT(VARCHAR(2),
                      dbo.WorkingHours.startMinutes) + ':00') AS newDate INTO #tempTable
FROM        dbo.Employees LEFT OUTER JOIN
                      dbo.TimeStamps ON dbo.Employees.employeeId = dbo.TimeStamps.employeeId LEFT OUTER JOIN
                      dbo.WorkingHours ON dbo.Employees.employeeId = dbo.WorkingHours.employeeId
WHERE    (dbo.Employees.isActive = 1) AND (CONVERT(VARCHAR(10), dbo.TimeStamps.startDate, 120) >= '2011-11-22') AND (CONVERT(VARCHAR(10),
                      dbo.TimeStamps.startDate, 120) <= '2011-12-08')

SELECT * FROM #tempTable
WHERE startDate > newDate
Avatar billede Syska Mester
09. december 2011 - 10:53 #5
Men ... jeg ville nok gemme lidt mere information om hver row, så har du har alt det du skal bruge for at lave din SELECT's, da dette kan blive meget langsom i fremtiden.

Hvis det er et eksisterende system, ja, så er der ikke så meget at gøre.
Avatar billede simsen Mester
09. december 2011 - 12:22 #6
Den skal jeg lige have uddybet - hvad ville du gemme mere af?
Avatar billede Syska Mester
09. december 2011 - 12:37 #7
Den converet du har lavet er jo statisk for hver row. Men det at lave convert er langsom for SQL og kan ikke indexeres. De data kunne ligeså godt have været i en column for sig selv.

mvh
Avatar billede simsen Mester
09. december 2011 - 12:53 #8
Ok - og din besked fik mig til at tænke.......nu havde jeg i forvejen lavet nogle tempTables (da jeg ikke kunne lave en where på en "beregning" jeg lavede i selecten) så jeg har tilføjet endnu en tempTable....Så den laver beregningen på antal rækker der bliver hentet ud i første hug, hvor den sorterer alle inaktive væk og ikke mindst kun giver rækker udfra en bestemt dato interval....

Normalt vil det sige, at den henter i første hug alle aktive medarbejdere udfra dags dato (sjældent de vil være interesseret i at hente ud for eks. for en måned). Og nu kunderne jeg laver det her til, vil altså ikke have SÅ mange medarbejdere...

Nu laver jeg så min "beregning" udfra den mindre antal rækker og smider over i en ny tempTable (da jeg ikke kan lave where *suk*)...

Min kode ser nu ud som følgende:

DECLARE @employeeId NVARCHAR(50)
DECLARE @employeeGroupId NVARCHAR(50)
DECLARE @lateMoreThanMinutes INT
DECLARE @fromDate DATETIME
DECLARE @toDate DATETIME

SET @employeeId = ''
SET @employeeGroupId = ''
Set @lateMoreThanMinutes = 5
Set @fromDate = '2011-11-22 20:20:20'
Set @toDate = '2011-12-08 20:20:20'

DROP TABLE #tempTable

SELECT    dbo.Employees.employeeId, dbo.Employees.employeeName, dbo.Employees.employeeGroupId, dbo.Employees.isActive, dbo.WorkingHours.startHours,
                      dbo.WorkingHours.startMinutes, dbo.TimeStamps.startDate, dbo.TimeStamps.regStartDate, dbo.TimeStamps.timeStampId, dbo.EmployeeGroups.employeeGroupName INTO #tempTable
FROM        dbo.Employees LEFT OUTER JOIN
                      dbo.EmployeeGroups ON dbo.Employees.employeeGroupId = dbo.EmployeeGroups.employeeGroupId LEFT OUTER JOIN
                      dbo.TimeStamps ON dbo.Employees.employeeId = dbo.TimeStamps.employeeId LEFT OUTER JOIN
                      dbo.WorkingHours ON dbo.Employees.employeeId = dbo.WorkingHours.employeeId
WHERE    (dbo.Employees.isActive = 1) AND (CONVERT(VARCHAR(10), dbo.TimeStamps.startDate, 120) >= @fromDate) AND (CONVERT(VARCHAR(10),
                      dbo.TimeStamps.startDate, 120) <= @toDate)



SELECT employeeId,employeeName,employeeGroupId, isActive, startHours, startMinutes, startDate, regStartDate, timeStampId, employeeGroupName, CONVERT(DATETIME,
                      CONVERT(VARCHAR(10), startDate, 120) + ' ' + CONVERT(VARCHAR(2), startHours) + ':' + CONVERT(VARCHAR(2),
                      startMinutes) + ':00') AS newDate INTO #tempTable2 FROM #tempTable

DROP TABLE #tempTable

SELECT employeeId,employeeName,employeeGroupId, isActive, startHours, startMinutes, startDate,regStartDate, timeStampId, newDate, employeeGroupName, DATEDIFF(Minute, newDate, startDate) AS diffDateMinutes INTO #tempTable3  FROM #tempTable2
WHERE (startDate > newDate)

DROP TABLE #tempTable2

IF @employeeId <> ''
BEGIN
    SELECT * FROM #TempTable3
    WHERE diffDateMinutes > @lateMoreThanMinutes AND employeeId = @employeeId
    ORDER BY startDate DESC
END
ELSE IF @employeeGroupId <> ''   
BEGIN
    SELECT * FROM #TempTable3
    WHERE diffDateMinutes > @lateMoreThanMinutes AND employeeGroupId = @employeeGroupId
    ORDER BY startDate DESC, employeeName
END
ELSE
BEGIN
    SELECT * FROM #TempTable3
    WHERE diffDateMinutes > @lateMoreThanMinutes
    ORDER BY startDate DESC, employeeName
END

DROP TABLE #tempTable3

Og smid så et svar og tak for den tilføjelse du lige kom med - den havde jeg ikke selv lige tænkt nok igennem...For ja om 3 år fra nu - så er tabellen jo nok temmelig stor *griner*
Avatar billede simsen Mester
14. december 2011 - 14:15 #9
Juhuuuu Buzzzz

Hvad virker bedst...at true med at sætte mig på dig eller kysse dig (jeg er en "gammel" tyk trunte til din information)...altså for at få dig til at smide et svar? *griner*
Avatar billede Syska Mester
14. december 2011 - 14:31 #10
Jeg kan slet ikke gennemskue alle de SQL statements.

Hvorfor er det lige du har en tempTable? Performance er SKOD i dem.

Hvorfor ikke bare have det hele i en query?

Lyder mere til at dit design af din database ikke helt er optimeret til det du vil med den. Jeg ville lave den om.

mvh
Avatar billede Syska Mester
14. december 2011 - 14:31 #11
svar
Avatar billede simsen Mester
14. december 2011 - 14:38 #12
Hvorfor jeg har alle de tempTables.....

Den første har jeg fordi jeg fik at vide af et klog hovede (dig), at lave

CONVERT(DATETIME,
                      CONVERT(VARCHAR(10), startDate, 120) + ' ' + CONVERT(VARCHAR(2), startHours) + ':' + CONVERT(VARCHAR(2),
                      startMinutes) + ':00') AS newDate

i min første select vil performance mæssigt være forfærdelig - nu laver jeg så en select, hvor jeg henter måske 20 rækker og så laver jeg min Convert på de 20 rækker....

Resten af de tempTables jeg har, fordi jeg hver gang, jeg forsøgte at lave en WHERE på det jeg dannede - f.eks. newDate, gik i fejl og sagde, at den ikke eksisterede....

altså når jeg forsøgte mig med:

SELECT employeeId,employeeName,employeeGroupId, isActive, startHours, startMinutes, startDate, regStartDate, timeStampId, employeeGroupName, CONVERT(DATETIME,
                      CONVERT(VARCHAR(10), startDate, 120) + ' ' + CONVERT(VARCHAR(2), startHours) + ':' + CONVERT(VARCHAR(2),
                      startMinutes) + ':00') AS newDate
FROM de forskellige tabeller
WHERE startDate > newDate

Her fik jeg så at vide, at newDate ikke eksisterede....
Avatar billede Syska Mester
14. december 2011 - 19:21 #13
1. Første er ingen tempTable.

2. tempTables er stadig langsommere end convert.

3. Her skal du lave convert igen, du kan ikke lave en reference til en column som ikke er trykket ud endnu.

Derfor jeg også mener det design af databasen er forkert, hvis det er sådanne ting du vil trække ud.

mvh
Avatar billede Syska Mester
14. december 2011 - 19:22 #14
Du kan måske lave et view af det ... som har nogen af de data som columns, det burde være hurtigere.
Avatar billede simsen Mester
15. december 2011 - 11:21 #15
Jeg kan ikke ændre designet. Det er afhængigt af ting, jeg får udefra systemet, som jeg ingen indflydelse har på overhovedet.

Noget jeg har overvejet i stedet.....

Ville det være smartere og ikke mindst hurtigere at smide det ind i C# delen - altså trække den første select ud - så snakker vi som skrevet om max 20 rækker, og så laver de efterfølgende ting i C# i stedet for at lave dem i SQL delen? ville det optimere perfomance?
Avatar billede Syska Mester
15. december 2011 - 12:54 #16
Hvis du ved det altid er få altal rækker, så kan det være en fordel.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Computerworld tilbyder specialiserede kurser i database-management

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester