Skip rows for specific time in SQL - sql

Need a help.
I have two timestamp columns, so basically I want to get the max and min value with a thirD column showing as timedifference. I am skipping any 12.am time so used the syntax below. ANy help how to achieve the third column, timedifference.. It is in DB2.
SELECT EMPID,MIN(STARTDATETIME),MAX(ENDDATETIME)
FROM TABLE
WHERE DATE(STARTDATETIME)= '2012-05-15' AND HOUR(STARTDATETIME)<>0 AND HOUR(ENDDATETIME)<>0
GROUP BY EMPID

You can use the results from that in an inner select, and use those values to define the TimeDifference column. My knowledge of DB2 is very limited, so I'm making some assumptions, but this should give you an idea. I'll update the answer if something is drastically incorrect.
Select EmpId,
MinStartDate,
MaxEndDate,
MaxEndDate - MinStartDate As TimeDifference
From
(
Select EMPID,
MIN(STARTDATETIME) As MinStartDate,
MAX(ENDDATETIME) As MaxEndDate
From Table
Where DATE(STARTDATETIME) = '2012-05-15'
And HOUR(STARTDATETIME) <> 0
And HOUR(ENDDATETIME) <> 0
Group By EMPID
) A

Related

SQL values disappear when using max dates

First time posting here and have a query that I hope someone maybe able to help with, i have tried to search for the answer but with no joy.
When i use the below SQL to find a value (in this case eb.annualvalue) it returns multiple values because no end dates have been entered into the eb table and there are too many employees without end dates for me to close down.
LEFT JOIN
(
SELECT
eb.empid, eb.bencode, eb.currencycode AS [currencycode], eb.notes AS [notes], eb.annualvalue
FROM
employeebenefit AS [eb]
WHERE
eb.bencode IN ('US 401K Plan')
AND (eb.enddate IS NULL OR eb.enddate >= '20180101')
)
AS eb26
ON eb26.empid = e.empid
However, when i use MAX startdate (code below) it returns the correct number or rows however, the eb.annualvalue figure disappears.
LEFT JOIN
(
SELECT
eb.empid, eb.bencode, eb.currencycode AS [currencycode], eb.notes AS [notes], eb.annualvalue
FROM
employeebenefit AS [eb]
WHERE
eb.bencode IN ('US 401K Plan')
AND (eb.enddate IS NULL OR eb.enddate >= '20180101')
AND (eb.startdate = (SELECT MAX(eb.startdate) FROM employeebenefit AS [eb]))
)
AS eb26
ON eb26.empid = e.empid
Any help would be greatly appreciated. Thanks Dan.
This sounds like a greatest-n-per-group problem, you just want one row per employee, from a table with many rows per employee. I'm not 100% clear on how you want to select that one row, but I can give an example.
Ideally, you would use ROW_NUMBER() but that only came in to effect from SQL Server 2008 onward.
The two commons alternative are:
- Join on your data twice. Once to find the "highest date" per user, again to find the whole row.
- Use a correlated sub-query to work out an individual's best row (still really joining twice)
Simple-self-join:
LEFT JOIN
(
SELECT
empid,
MAX(startdate) AS max_startdate
FROM
employeebenefit
WHERE
bencode IN ('US 401K Plan')
AND (enddate IS NULL OR enddate >= '20180101')
GROUP BY
empid
)
latest_employeebenefit
ON latest_employeebenefit.empid = e.empid
LEFT JOIN
employeebenefit
ON employeebenefit.empid = latest_employeebenefit.empid
AND employeebenefit.startdate = latest_employeebenefit.max_startdate
AND employeebenefit.bencode IN ('US 401K Plan')
AND (employeebenefit.enddate IS NULL OR employeebenefit.enddate >= '20180101')
This has the "feature" that if two such records both match the max_startdate (a tie) then both will come through. Often that is impossible, often it's desirable, it depends on your data and your needs.
Correlated-sub-query for join:
LEFT JOIN
employeebenefit
ON employeebenefit.id =
(
SELECT TOP(1) lookup.id
FROM employeebenefit AS lookup
WHERE lookup.empid = e.empid -- the correlated bit
AND lookup.bencode IN ('US 401K Plan')
AND (lookup.enddate IS NULL OR lookup.enddate >= '20180101')
ORDER BY lookup.startdate DESC
)
This is slightly different in that it always returns just one row. If there can be a tie when only sorting by startdate it's generally best to add another column to the ORDER BY, even if it's just an id column, to ensure the results are deterministic.
You can use the code bellow , if I undestood your question
OUTER APPLY
(
SELECT TOP 1
eb.empid, eb.bencode, eb.currencycode AS [currencycode], eb.notes AS [notes], eb.annualvalue
FROM
employeebenefit AS [eb]
WHERE
eb.empid = e.empid
AND eb.bencode IN ('US 401K Plan')
AND (eb.enddate IS NULL OR eb.enddate >= '20180101')
ORDER BY
eb.startdate DESC
)
AS eb26

Select SQL table data

I have a table as shown in image. Here user 'A' has no outtime where Id=2. If I select UserId,Name,MIN(inTime) and MAX(outtime) from MyTable ,then i will get First InTime and Last OutTime . Instead of selecting like that, I want to set User 'A' last outtime as null. How is it possible?.
Thanks in Advance
I assume you are using SQL Server:
select *
from(select name, userid, dateatt
from table
group by name, userid, dateatt)t
cross apply(select top 1 intime from table
where userid=t.userid and dateatt=t.dateatt order by id)i
cross apply(select top 1 outtime from table
where userid=t.userid and dateatt=t.dateatt order by id desc)o
By default, MAX and MIN do not include NULL when evaluating data.
See the below query I have modified for you taken from article here.
We will use COALESCE to replace any NULL EndDate with a date that is in the future that will not be coming up in our data anywhere, December 31, 2099 seems like a reasonable date for this. Next we take the MAX of the dates, which if NULL will evaluate as 12/31/2099 and be greater than any other date in our table. Wrap that in a CASE statement to replace the date 12/31/2099 back to NULL and group our data by StoreID.
SELECT
Name,
CASE WHEN MAX(COALESCE(outtime, ’12/31/2099′)) = ’12/31/2099′ THEN NULL ELSE MAX(outtime) END AS outtime
FROM WorkSchedule
GROUP BY Name

How to get datetime duplicate rows in SQL Server?

Im trying to find duplicate DATETIME rows in a table,
My column has datetime values such as 2015-01-11 11:24:10.000.
I must get the duplicates in 2015-01-11 11:24 type. Rest of it, not important. I can get the right value when I use SELECT with 'convert(nvarchar(16),column,121)', but when I put this in my code, I have to use 'group by' statement, so
My code is:
SELECT ID,
RECEIPT_BARCODE,
convert(nvarchar(16),TRANS_DATE,121),
PTYPE
FROM TRANSACTION_HEADER
WHERE TRANS_DATE BETWEEN '11.01.2015' AND '12.01.2015'
GROUP BY ID,RECEIPT_BARCODE,convert(nvarchar(16),TRANS_DATE,121),PTYPE
HAVING COUNT(convert(nvarchar(16),TRANS_DATE,121)) > 1
Since SQL forces me to use 'convert(nvarchar(16),TRANS_DATE,121)' in GROUP BY statement, I can't get the duplicate values.
Any idea for this?
Thanks in advance.
If you want the actual rows that are duplicated, then use window functions instead:
SELECT th.*, convert(nvarchar(16),TRANS_DATE,121)
FROM (SELECT th.*, COUNT(*) OVER (PARTITION BY convert(nvarchar(16),TRANS_DATE,121)) as cnt
FROM TRANSACTION_HEADER th
WHERE TRANS_DATE BETWEEN '11.01.2015' AND '12.01.2015'
) th
WHERE cnt > 1;
SELECT ID,RECEIPT_BARCODE,convert(nvarchar(16),TRANS_DATE,121), PTYPE ,COUNT(*)
FROM TRANSACTION_HEADER
WHERE TRANS_DATE BETWEEN '11.01.2015' AND '12.01.2015'
GROUP ID,RECEIPT_BARCODE,convert(nvarchar(16),TRANS_DATE,121), PTYPE
HAVING COUNT(*)>1;
I think you can use count(*) directly here.try the above one.

Why would the query show data from the wrong month?

I have a query:
;with date_cte as(
SELECT r.starburst_dept_name,r.monthly_past_date as PrevDate,x.monthly_past_date as CurrDate,r.starburst_dept_average - x.starburst_dept_average as Average
FROM
(
SELECT *,ROW_NUMBER() OVER(PARTITION BY starburst_dept_name ORDER BY monthly_past_date) AS rowid
FROM intranet.dbo.cse_reports_month
) r
JOIN
(
SELECT *,ROW_NUMBER() OVER(PARTITION BY starburst_dept_name ORDER BY monthly_past_date) AS rowid
FROM intranet.dbo.cse_reports_month
Where month(monthly_past_date) > month(DATEADD(m,-2,monthly_past_date))
) x
ON r.starburst_dept_name = x.starburst_dept_name AND r.rowid = x.rowid+1
Where r.starburst_dept_name is NOT NULL
)
Select *
From date_cte
Order by Average DESC
So doing some testing, I have alter some columns data, to see why it gives me certain information. I don't know why when I run the query it gives my a date column that should not be there from "january" (row 4) like the picture below:
The database has more data that has the same exact date '2014-01-25 00:00:00.000', so I'm not sure why it would only get that row and compare the average?
I did before I run the query alter the column in that row and change the date? But I'm not sure if that would have something to do with it.
UPDATE:
I have added the sqlfinddle,
What I would like to get it subtract the average
from last_month - last 2 month ago.
It Was actually working until I made a change and alter the data.
I made the changes to test a certain situation, which obviously lead
to learning that there are flaws to the query.
Based on your SQL Fiddle, this eliminates joins from prior than month-2 from showing up.
SELECT
thismonth.starburst_dept_name
,lastmonth.monthtly_past_date [PrevDate]
,thismonth.monthtly_past_date [CurrDate]
,thismonth.starburst_dept_average - lastmonth.starburst_dept_average as Average
FROM dbo.cse_reports thismonth
inner join dbo.cse_reports lastmonth on
thismonth.starburst_dept_name = lastmonth.starburst_dept_name
AND month(DATEADD(MONTH,-1,thismonth.monthtly_past_date))=month(lastmonth.monthtly_past_date)
WHERE MONTH(thismonth.monthtly_past_date)=month(DATEADD(MONTH,-1,GETDATE()))
Order by thismonth.starburst_dept_average - lastmonth.starburst_dept_average DESC

filtering rows by checking a condition for group in one statement only

I have the following statement:
SELECT
(CONVERT(VARCHAR(10), f1, 120)) AS ff1,
CONVERT(VARCHAR(10), f2, 103) AS ff2,
...,
Bonus,
Malus,
ClientID,
FROM
my_table
WHERE
<my_conditions>
ORDER BY
f1 ASC
This select returns several rows for each ClientID. I have to filter out all the rows with the Clients that don't have any row with non-empty Bonus or Malus.
How can I do it by changing this select by one statement only and without duplicating all this select?
I could store the result in a #temp_table, then group the data and use the result of the grouping to filter the temp table. - BUT I should do it by one statement only.
I could perform this select twice - one time grouping it and then I can filter the rows based on grouping result. BUT I don't want to select it twice.
May be CTE (Common Table Expressions) could be useful here to perform the select one time only and to be able to use the result for grouping and then for selecting the desired result based on the grouping result.
Any more elegant solution for this problem?
Thank you in advance!
Just to clarify what the SQL should do I add an example:
ClientID Bonus Malus
1 1
1
1 1
2
2
3 4
3 5
3 1
So in this case I don't want the ClientID=2 rows to appear (they are not interesting). The result should be:
ClientID Bonus Malus
1 1
1
1 1
3 4
3 5
3 1
SELECT Bonus,
Malus,
ClientID
FROM my_table
WHERE ClientID not in
(
select ClientID
from my_table
group by ClientID
having count(Bonus) = 0 and count(Malus) = 0
)
A CTE will work fine, but in effect its contents will be executed twice because they are being cloned into all the places where the CTE is being used. This can be a net performance win or loss compared to using a temp table. If the query is very expensive it might come out as a loss. If it is cheap or if many rows are being returned the temp table will lose the comparison.
Which solution is better? Look at the execution plans and measure the performance.
The CTE is the easier, more maintainable are less redundant alternative.
You haven't specified what are data types of Bonus and Malus columns. So if they're integer (or can be converted to integer), then the query below should be helpful. It calculates sum of both columns for each ClientID. These sums are the same for each detail line of the same client so we can use them in WHERE condition. Statement SUM() OVER() is called "windowed function" and can't be used in WHERE clause so I had to wrap your select-list with a parent one just because of syntax.
SELECT *
FROM (
SELECT
CONVERT(VARCHAR(10), f1, 120) AS ff1,
CONVERT(VARCHAR(10), f2, 103) AS ff2,
...,
Bonus,
Malus,
ClientID,
SUM(Bonus) OVER (PARTITION BY ClientID) AS ClientBonusTotal,
SUM(Malus) OVER (PARTITION BY ClientID) AS ClientMalusTotal
FROM
my_table
WHERE
<my_conditions>
) a
WHERE ISNULL(a.ClientBonusTotal, 0) <> 0 OR ISNULL(a.ClientMalusTotal, 0) <> 0
ORDER BY f1 ASC