SQL Server conditional query - sql-server

I have a table for attendance entries looking like this :
I need a query to export the following format :
which present the Check-in and Check-out timings using British/French format (103)
I tried the following query :
SELECT
UserID,
(SELECT MIN(checktime)
FROM [FingerPrint].[dbo].[CHECKINOUT] I
WHERE CONVERT(VARCHAR(10), i.checktime, 111) = CONVERT(VARCHAR(10), p.checktime, 111)
AND i.userid = p.userid),
(SELECT MAX(checktime)
FROM [FingerPrint].[dbo].[CHECKINOUT] I
WHERE CONVERT(VARCHAR(10), i.checktime, 111) = CONVERT(VARCHAR(10), p.checktime, 111)
AND i.userid = p.userid)
FROM
[FingerPrint].[dbo].[CHECKINOUT] p
GROUP BY
p.checktime, p.UserID
Basically I need a query to select the minimum time (check-in) and maximum time (check-out) for each day using the export format above, yet when there is no value for check-in and check-out, then query should return (null) for time.

So basically you start with something like this:
SELECT UserId,
CAST(CheckTime As Date) As CheckDate,
MIN(CheckTime) As CheckIn,
MAX(CheckTime) As CheckOut
FROM [FingerPrint].[dbo].[CHECKINOUT]
GROUP BY UserId, CAST(CheckTime As Date)
For older versions of sql server (2005, 2000), you can use convert to char(10) to isolate the date part of the datetime column:
SELECT UserId,
CONVERT(char(10), CheckTime, 102) As CheckDate, /*Convert datetime format to Date*/
MIN(CheckTime) As CheckIn,
MAX(CheckTime) As CheckOut
FROM [FingerPrint].[dbo].[CHECKINOUT]
GROUP BY UserId, CONVERT(char(10), CheckTime, 102)
see fiddle here
Then you need to figure out what you want to display if the user have only one record for a day.
Also, what happens on night shifts, when a user checks in on one date, and checks out on the other date?
A better solution would be to add a bit column to specify if the record is for check in or for check out.
Update
Using case you can check if the current time is before or after whatever time of day you want to set up as the delimiter between check in and check out. In this example I've used 12 pm.
SELECT UserId,
CONVERT(char(10), CheckTime, 102) As CheckDate, /*Convert datetime format to Date*/
CASE WHEN MIN(CheckTime) <> MAX(CheckTime) THEN
MIN(CheckTime)
ELSE
CASE WHEN MIN(CheckTime) < DATEADD(Hour, 12, CONVERT(Datetime, CONVERT(char(10), CheckTime, 102), 102)) THEN
NULL
ELSE
MIN(CheckTime)
END
END As CheckIn,
CASE WHEN MIN(CheckTime) <> MAX(CheckTime) THEN
MAX(CheckTime)
ELSE
CASE WHEN MAX(CheckTime) > DATEADD(Hour, 12, CONVERT(Datetime, CONVERT(char(10), CheckTime, 102), 102)) THEN
NULL
ELSE
MAX(CheckTime)
END
END As CheckOut
FROM [CHECKINOUT]
GROUP BY UserId, CONVERT(char(10), CheckTime, 102)
Here is the relevant fiddle.

Related

Combine two query and display in single line

I am using the below code to find the sales by credit card and cash and the current output show as below but I want to get the card and cash sales in single line.
current output:
expected output:
SELECT CONVERT(VARCHAR(10), CreateDate, 103) DT,SUM(AMOUNT),NULL FROM JnlDetails WHERE JnlDetails.CreateDate > '2021-05-01'
AND ACCOUNTID = '000153200101'
GROUP BY CONVERT(VARCHAR(10), CreateDate, 103)
UNION ALL
SELECT CONVERT(VARCHAR(10), CreateDate, 103) DT,NULL,SUM(AMOUNT) FROM JnlDetails WHERE JnlDetails.CreateDate > '2021-05-01'
AND ACCOUNTID = '000153200201'
GROUP BY CONVERT(VARCHAR(10), CreateDate, 103)
ORDER BY DT
Is there any other option available to achieve this without Union? Both the information's (Card and Sales) in the same table, based on the accountid we can split.
Using a case expression you can conditionally sum your values
select Convert(varchar(10), CreateDate, 103) DT,
Sum (case when ACCOUNTID = '000153200101' then AMOUNT end) as Cash,
Sum (case when ACCOUNTID = '000153200201' then AMOUNT end) as Card
from JnlDetails
where JnlDetails.CreateDate > '2021-05-01'
and ACCOUNTID in ('000153200101','000153200201')
group by Convert(varchar(10), CreateDate, 103)

Rolling 3 Years of data with desired format

Start Date = 2016-03-01
End Date = 2019-02-15
I need the query/Function which should retrive the below result based on start and end date. I have a query to frame the result .But i need some query/function to retrive result set in 5 to 10 sec with performance
You mean like
SELECT * FROM table WHERE [start date]>='2016-03-01' AND [end date]<='2019-02-15'
Am I missing something? This seems too simple to ask as a question
If your problem is performance perhaps consider indexing start and end date columns, and if you're only getting a couple other values from the table include those in the index too.
CREATE INDEX IX_table_startdate_enddate
ON schema.table ([start date], [end date])
INCLUDE (othercolumn1, othercolumn2);
It means that queries like:
SELECT othercolumn1, othercolumn2 FROM table
WHERE [start date]>='2016-03-01' AND [end date]<='2019-02-15'
Can be answered from the index without having to connect the index to the table to pull the desired data
If you still can't wrong enough out of it after that perhaps you have a design flaw in your app; pilling a db for a massive amount of data in a tight interval could be solved another way like only emitting events when data actually changes
It's just occurred to me you're probably looking for a query to generate that result set from nothing. In sqlserver we can use a recursive cte:
DECLARE #dateFrom DATE = '2016-03-01'
DECLARE #dateTo DATE = '2019-02-15'
with d as (
SELECT #datefrom as m
UNION ALL
SELECT DATEADD(MONTH,1,reqDate)
FROM d
WHERE DATEADD(MONTH,1,reqDate) <= #dateto
),
SELECT
CONCAT(
DATENAME(MONTH, #dateFrom), ' ',
CASE WHEN MONTH(d.m) < MONTH(#dateFrom) THEN YEAR(d.m) - 1 ELSE YEAR(d.m) END, '-',
DATENAME(MONTH, #dateTo), ' ',
CASE WHEN MONTH(d.m) < MONTH(#dateFrom) THEN YEAR(d.m) ELSE YEAR(d.m) +1 END
) as range,
MONTH(d.m) as month,
d.m as startdate,--do not use spaces in column names
CASE WHEN #dateTo < EOMONTH(d.m) then #dateTo ELSE EOMONTH(d.m) END as enddate --or dateadd 1 month then dateadd -1 day if you don't have eomonth
FROM d
OPTION(MAXRECURSION 0);
Same format with your result try it.
DECLARE #StartDate DATETIME, #EndDate DATETIME
SET #StartDate = '2016-03-01'
SET #EndDate = '2038-02-15'
;WITH CTEs AS
(
SELECT #StartDate as [Start Date]
UNION ALL
SELECT DATEADD(MONTH,1,[Start Date])
FROM CTEs WHERE DATEADD(MONTH,1,[Start Date]) <= #EndDate
)
SELECT
CONCAT(
DATENAME(MONTH, #StartDate), ' ',
CASE WHEN MONTH([Start Date]) < MONTH(#StartDate) THEN YEAR([Start Date]) - 1 ELSE YEAR([Start Date]) END, '-',
DATENAME(MONTH, #EndDate), ' ',
CASE WHEN MONTH([Start Date]) < MONTH(#StartDate) THEN YEAR([Start Date]) ELSE YEAR([Start Date]) + 1 END
) AS [Range],
MONTH([Start Date]) AS [Month],
CONVERT(VARCHAR(10),[Start Date],101) AS [Start Date],
CONVERT(VARCHAR(10),(CASE WHEN [Start Date] <> DATEFROMPARTS(YEAR(#EndDate),MONTH(#EndDate),1)
THEN EOMONTH([Start Date])
ELSE #EndDate
END),101) AS [End Date]
FROM CTEs
OPTION(MAXRECURSION 0);

Check order row depending on result query in sql server

I have a table checks2:
AllTaskNo int,
CheckQuosimaNo int,
Masroof numeric(18,3),
Maqbood numeric(18,3),
Date1 smalldatetime
I have a query to get balance:
SELECT
AllTaskNo
,CheckQuosimaNo
,Masroof
,Maqbood
,Date
,(SELECT 0 + SUM(Maqbood - Masroof) AS Expr1
FROM Checks2 AS t2
WHERE (BankNo = 6)
AND (CheckQuosimaNo <= Checks2.CheckQuosimaNo)
AND (Date1 BETWEEN CONVERT(DATETIME, '01/01/2014', 103)
AND CONVERT(DATETIME, '31/10/2015', 103)) AND AllTaskNo
IN (SELECT No
FROM AllTasks
WHERE (BankNo = 6)
AND (Date BETWEEN CONVERT(DATETIME, '01/01/2014', 103)
AND CONVERT(DATETIME, '31/10/2015', 103))))) AS NetAmount
FROM
Checks2
WHERE
(BankNo = 6)
AND
(Date1 BETWEEN CONVERT(DATETIME, '01/01/2014', 103)
AND CONVERT(DATETIME, '31/10/2015', 103))
ORDER BY
BankNo
,Date1
,CheckQuosimaNo
the result is:
enter image description here
I need to make a formula (like excel for example NetAmount = NetAmount before + Maqbood - Masroof)
I expect that the selected row in NetAmount = 656360 but then query produce NetAmount=5567675.976
How can I fix this problem
There are many way to do this like Over and Correlated Sub Queries
Over:
SELECT
AllTaskNo ,Maqbood , Masroof,
SUM(-1*Maqbood +Masroof) OVER (ORDER BY AllTaskNo ) AS NetAmount
FROM Checks2 T1
Correlated Sub Queries (Need Sql server 2014+)
SELECT
AllTaskNo ,Maqbood , Masroof,
(
SELECT
SUM(-1*Maqbood +Masroof)
FROM Checks2 T2
WHERE T2.AllTaskNo <=T1.AllTaskNo
) AS NetAmount FROM Checks2 T1
Feel free to comment if you need any further assistance on this item
I have been solve my problem by my own solution ... I think there is a shorter solution .. but any way I get what I want... My solution is:
1- Make a table (Checks3) with a new field named (rank) which is the correct order of the command result.
2- Create a new command mostly like the first one containing the (bank balance formula).
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[Checks3]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table [dbo].[Checks3]
SELECT Checks2.BankNo, Checks2.AllTaskNo, Checks2.CheckQuosimaNo, Checks2.Masroof, Checks2.Maqbood, Checks2.Date1, rank() OVER (ORDER BY checks2.date1, checks2.CheckQuosimaNo) as rank
INTO Checks3
FROM Checks2 INNER JOIN
AllTasks ON Checks2.AllTaskNo = AllTasks.No where Checks2.BankNo =6 and (Checks2.[Date1] BETWEEN CONVERT(DATETIME, '01/10/2015', 103) AND CONVERT(DATETIME,'31/10/2015', 103)) ORDER BY CHECKS2.BankNo, CHECKS2.CheckQuosimaNo
SELECT Checks3.AllTaskNo, Checks3.CheckQuosimaNo, Checks3.Masroof, Checks3.Maqbood, Checks3.Date1,
( SELECT 0+SUM(t2.Maqbood - t2.Masroof) FROM Checks3 t2
WHERE t2.BankNo =6 and t2.rank <= Checks3.rank
and (t2.[Date1] BETWEEN CONVERT(DATETIME, '01/10/2014', 103) AND CONVERT(DATETIME,'31/10/2015', 103))
) as NetAmount
FROM Checks3
where Checks3.BankNo =6 and (Checks3.[Date1] BETWEEN CONVERT(DATETIME, '01/10/2014', 103) AND CONVERT(DATETIME,'31/10/2015', 103)) ORDER BY CHECKS3.RANK

How to use CAST to return date column with just month and day

Using a CAST function in a select statement, how do I return a date column with just the month and day?
SELECT CAST(DateAdded as date) -- returns column with date format
, CAST(DateAdded as time) -- returns only time
, CAST(DateAdded as ...) --return only month and day
Something like this(replacing the getdate function with your date column):
select
cast(getdate() as date) as FullDate
, right(cast(getdate() as date),5) as MonthDay
, cast(getdate() as time) as TimeofDay
Warning: this may depend on which version of SQL Server you are using.
SELECT CONVERT(VARCHAR(5), GETDATE(), 4)
21.10
OR
SELECT CONVERT(VARCHAR(5), GETDATE(), 5)
21-10
OR
SELECT CONVERT(VARCHAR(5), GETDATE(), 3)
21/10
OR
SELECT CONVERT(VARCHAR(2),MONTH(GETDATE())) + '-'+ CONVERT(VARCHAR(2),DAY(GETDATE()))
10-21

How to get a time and Date Separately?

Using SQL Server 2005
Table1
Time
12/05/2009 08:30:49
12/05/2009 17:00:00
13/05/2009 21:00:00
...,
Above Table Both values are same column, Here I want to separate column like Date and Time
Expected Output
Date Time
12/05/2009 08:30:49
12/05/2009 17:00:00
13/05/2009 21:00:00
You can retrieve separate date and time parts like:
SELECT
CONVERT(VARCHAR(10),DateField,101) as DatePart,
CONVERT(VARCHAR(10),DateField,108) as TimePart
FROM YourTable
For more information, see the CONVERT documentation.
The code snippet above returns the DataPart and TimePart as a varchar. If you're interested in retrieving them as a datetime field, try:
SELECT
DATEADD(D, 0, DATEDIFF(D, 0, DateField)) as DatePart,
DATEADD(day, -DATEDIFF(D, 0, DateField), DateField) as TimePart
FROM YourTable
The following query returns the date and time respectively for the current system date/time:
SELECT
CONVERT(VARCHAR(8) , GETDATE() , 108) AS [time],
CONVERT(VARCHAR(10) , GETDATE() , 101) AS [date]
select
CONVERT(VARCHAR(8), GETDATE(), 108) as [time],
CONVERT(VARCHAR(8), GETDATE(), 111) as [date]
See this reference for all formats
Just a slight modification to pmarflee's answer, because you appear to be wanting the date as dd/mm/yy rather than mm/dd/yy:
SELECT CONVERT(VARCHAR(8) , GETDATE() , 108) AS [time], CONVERT(VARCHAR(10) , GETDATE() , 103) AS [date]

Resources