Conversion of string to DateTime & using conversion in Where Clause - DateDiff - sql

I have a string column that contains dates. I want to convert string to date so that i can use the Date Logic ahead.
I have converted the string to DateTime but while applying the logic in the Where clause it doesn't allow me to use the Column.
SELECT a.code,
CONVERT(DATETIME,b.[FieldValue],103) as [Date1]
FROM [dbo].employeedetail as A join [dbo].CustomeFieldDetail as B
on A.Id = B.EMployeeid
WHERE a.empstatus = 1
AND B.CustomeFieldName = 'PASSPORT' AND
( Datediff(dd, Getdate(), Dateadd(yyyy, Datediff(yyyy, b.[Date1],
Getdate())
+
1, b.[Date1]))
+ 1 ) % 366 = 50
Can anyone help me?

Use APPLY to introduce a reusable expression.
SELECT a.code,
c.[Date1]
FROM [dbo].employeedetail as A
JOIN [dbo].CustomeFieldDetail as B ON A.Id = B.EMployeeid
CROSS APPLY (
SELECT CONVERT(DATETIME,b.[FieldValue],103) as [Date1]
) c
WHERE a.empstatus = 1
AND B.CustomeFieldName = 'PASSPORT' AND
( Datediff(dd, Getdate(), Dateadd(yyyy, Datediff(yyyy, c.[Date1],
Getdate())
+
1, c.[Date1]))
+ 1 ) % 366 = 50
A better solution is store dates as DATE, DATETIME, not strings.

Using CTE results in an even more compact query:
WITH B AS (
SELECT *, CONVERT(DATETIME, [FieldValue], 103) AS [Date1]
FROM [dbo].CustomeFieldDetail
WHERE (CustomeFieldName = 'PASSPORT')
)
SELECT A.code, B.[Date1]
FROM [dbo].EmployeeDetail AS A JOIN B ON A.Id = B.EMployeeid
WHERE (A.empstatus = 1)
AND (((DATEDIFF(dd, GETDATE(),
DATEADD(yyyy, DATEDIFF(yyyy, B.[Date1], GETDATE()) + 1, B.[Date1])) + 1)
% 366) = 50)

Related

Sql where Condition execution not working

I have the following query logic
Show comments which is not deleted
Show comments which is deleted after created, within a timespan of 30 days before today(Today - Createddate <= 30)
Below is the logic which I wrote, but I don't think it is working correct.
SELECT string_agg(
CAST(CONCAT_WS(',',
c.Id,
COALESCE(c.ParentCommentId, 0),
c.TotalRatingsCount,
c.Pinned,
c.IsDeleted,
FORMAT(c.CreatedDate, 'yyyy-MM-dd HH:mm:ss')) AS VARCHAR(MAX))
, '|')
FROM Comments c
WHERE c.DiscussionId = d.Id
and
((c.IsDeleted = 0 and DATEDIFF(day, c.CreatedDate , GETDATE()) >= 30))
or
(((c.IsDeleted = 1 or c.IsDeleted =0) and DATEDIFF(day, c.CreatedDate , GETDATE()) <= 30))
SELECT string_agg(
CAST(CONCAT_WS(',',
c.Id,
COALESCE(c.ParentCommentId, 0),
c.TotalRatingsCount,
c.Pinned,
c.IsDeleted,
FORMAT(c.CreatedDate, 'yyyy-MM-dd HH:mm:ss')) AS VARCHAR(MAX))
, '|')
FROM Comments c
WHERE c.DiscussionId = d.Id
and
((c.IsDeleted = 0 )
or
((c.IsDeleted = 1 ) and DATEDIFF(day, c.CreatedDate , GETDATE()) <= 30))

SQL Server 2014 Select total for each day

Hello I am working on a dataset for a report in SSRS
and I have a query which gives the total requests in the backlog :
SELECT
COUNT(*) as NB
FROM p_rqt WITH (NOLOCK)
INNER JOIN p_cpy WITH (NOLOCK) ON p_cpy.CpyInCde = p_rqt.OrigCpyInCde
WHERE
CpyTypInCde IN (27, 31)
AND p_rqt.RqtNatInCde IN (74, 75, 76)
AND HeadRqtInCde = 0
AND p_rqt.OrigCpyInCde LIKE CASE WHEN #Client = 0 THEN '%' ELSE #Client END
AND ((RcvDte < DATEADD(day, 1, #DateDeb) AND RqtEndDte IS NULL) OR
(RcvDte < DATEADD(day, 1, #DateDeb) AND RqtEndDte > DATEADD(day, 1, #DateDeb)))
and I want to retrieve the total amount left per day.
I tried lot of things like this :
SELECT CONVERT(date,rcvdte,103), count(*) as nb
FROM p_rqt p WITH (NOLOCK)
INNER JOIN p_cpy WITH (NOLOCK) ON p_cpy.CpyInCde = p.OrigCpyInCde
WHERE
CpyTypInCde IN (27, 31)
AND p.RqtNatInCde IN (74, 75, 76)
AND HeadRqtInCde = 0
AND ((RcvDte < DATEADD(day, 1, '20170901') AND RqtEndDte IS NULL) OR (RcvDte < DATEADD(day, 1, '20170901') AND RqtEndDte > DATEADD(day, 1, '20170901')))
group by CONVERT(date,rcvdte,103)
order by CONVERT(date,rcvdte,103)
I tried inner join subqueries, Sum and other stuff
but all I can manage to do is to have the number of records added per day
and I want something like this :
date: NB:
01/01/2017 1950
02/01/2017 1954 (+4 items)
03/01/2017 1945 (-9 items)
Thank you
Use LAG:
WITH cte AS (
SELECT
CONVERT(date, rcvdte, 103) AS date,
COUNT(*) AS nb
FROM p_rqt p WITH (NOLOCK)
INNER JOIN p_cpy WITH (NOLOCK)
ON p_cpy.CpyInCde = p.OrigCpyInCde
WHERE
CpyTypInCde IN (27, 31) AND
p.RqtNatInCde IN (74, 75, 76) AND
HeadRqtInCde = 0 AND
((RcvDte < DATEADD(day, 1, '20170901') AND RqtEndDte IS NULL) OR (RcvDte < DATEADD(day, 1, '20170901') AND RqtEndDte > DATEADD(day, 1, '20170901')))
GROUP BY CONVERT(date, rcvdte, 103)
ORDER BY CONVERT(date, rcvdte, 103)
)
SELECT
t1.date,
(SELECT SUM(t2.nb) FROM cte t2 WHERE t2.date <= t1.date) AS nb,
CASE WHEN t1.nb - LAG(t1.nb, 1, t1.nb) OVER (ORDER BY t1.date) > 0
THEN '(+' + (t1.nb - LAG(t1.nb, 1, t1.nb) OVER (ORDER BY t1.date)) + ' items)'
ELSE '(' + (t1.nb - LAG(t1.nb, 1, t1.nb) OVER (ORDER BY t1.date)) + ' items)'
END AS difference
FROM cte t1
ORDER BY t1.date;
So i found a solution but it is really slow,
i still post the answer anyway
DECLARE #Tb TABLE ( Colonne1 Datetime, Colonne2 INT )
DECLARE #Debut Datetime = '01/09/2017'
WHILE #Debut < '13/09/2017'
BEGIN
DECLARE #Compteur int = (
SELECT
COUNT(1) NB
FROM p_rqt WITH (NOLOCK)
INNER JOIN p_cpy WITH (NOLOCK) ON p_cpy.CpyInCde = p_rqt.OrigCpyInCde
WHERE
CpyTypInCde IN (27, 31)
AND p_rqt.RqtNatInCde IN (74, 75, 76)
AND HeadRqtInCde = 0
AND p_rqt.OrigCpyInCde LIKE '%'
AND (
(RcvDte < #Debut AND RqtEndDte IS NULL)
OR
(RcvDte < #Debut AND RqtEndDte > #Debut)
)
)
INSERT INTO #Tb (Colonne1, Colonne2) VALUES (#Debut, #Compteur)
SET #Debut = DATEADD(day, 1, #Debut)
IF #Debut > '13/09/2017'
BREAK
ELSE
CONTINUE
END
SELECT * FROM #Tb

SQL Count with zero values

I want to create a graph for my dataset for the last 24 hours.
I found a solution that works but this is pretty bad since the table I am outer joining cotains every single row in the DB since I am using the (now deprecated) "all" parameter in the group by.
Here is the solution that currently kind of works.
First I declare the date intervals that is 24 hours back in time from now. I declare it twice so I can use it later in the procedure aswell.
Declare #StartDate datetime = dateadd(hour, -24, getdate())
Declare #StartDateProc datetime = dateadd(hour, -24, getdate())
Declare #EndDate datetime = getdate()
I populate the dates into a temp table including a special formated datetsring.
create table #tempTable
(
Date datetime,
DateString varchar(11)
)
while #StartDate <= #EndDate
begin
insert into #tempTable (Date, DateString)
values (#StartDate, convert(varchar(8), #StartDate, 5) + '-' + convert(varchar(2), #StartDate, 108));
SET #StartDate = dateadd(hour,1, #StartDate);
end
This gives me data that looks like this:
Date DateString
---------------------------------------------
2015-12-09 13:59:01.970 09-12-15-13
2015-12-09 14:59:01.970 09-12-15-14
2015-12-09 15:59:01.970 09-12-15-15
2015-12-09 16:59:01.970 09-12-15-16
So what I want is to join my dataset on the matching date string and show the date even if the matching rows is zero.
Here is the rest of the query
select
Date = c.Date,
Amount = sum(c.Amount)
from
DbTable a
outer apply
(select
Date = b.DateString,
Amount = count(*)
from
#tempTable b
where
convert(varchar(8), a.DateColumn, 5) + '-' + convert(varchar(2), a.DateColumn, 108) = b.DateString
group by all
b.DateString) c
where
a.SomeParameter = 'test' and
a.DateColumn >= #StartDateProc and
a.DateColumn <= #EndDate
group by
c.Date
drop table #tempTable
Test to show actual data:
Declare #StartDate datetime = dateadd(hour, -24, getdate())
Declare #EndDate datetime = getdate()
select
dateString = convert(varchar(8),a.DateColumn,5) + '-' + convert(varchar(2),a.DateColumn, 108),
Amount = COUNT(*)
from
DbTable a
where
a.someParameter = 'test' and
a.DateColumn>= dateadd(hour, -24, getdate()) and
a.DateColumn<= getdate()
group by
convert(varchar(8),a.DateColumn,5) + '-' + convert(varchar(2),a.DateColumn, 108)
First output rows:
dateString Amount
09-12-15-14 1
09-12-15-15 1
09-12-15-16 1
09-12-15-17 3
09-12-15-18 1
09-12-15-22 3
09-12-15-23 2
As you can see here there is no data for the times from 19.00 to 21.00. This is how I want the data to be displayed:
dateString Amount
09-12-15-14 1
09-12-15-15 1
09-12-15-16 1
09-12-15-17 3
09-12-15-18 1
09-12-15-19 0
09-12-15-20 0
09-12-15-21 0
09-12-15-22 3
09-12-15-23 2
Normally, this would be approached with left join rather than outer apply. The logic is simple: keep all rows in the first table along with any matching information from the second. This means put the dates table first:
select tt.DateString, count(t.DateColumn) as Amount
from #tempTable tt left join
DbTable t
on convert(varchar(8), t.DateColumn, 5) + '-' + convert(varchar(2), t.DateColumn, 108) = tt.DateString and
t.SomeParameter = 'test'
where tt.Date >= #StartDateProc and
tt.Date <= #EndDate
group by tt.DateString;
In addition, your comparison for the dates seems overly complex, but if it works for you, it works.
The best bet here would be to use DATETIME type itself and not to lose the opportunity to use indexes:
Declare #d datetime = GETDATE()
;WITH cte1 AS(SELECT TOP 25 -1 + ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) h
FROM master..spt_values),
cte2 AS(SELECT DATEADD(hh, -h, #d) AS startdate,
DATEADD(hh, -h + 1, #d) AS enddate
FROM cte1)
SELECT c.startdate, c.enddate, count(*) as amount
FROM cte2 c
LEFT JOIN DbTable a ON a.DateColumn >= c.startdate AND
a.DateColumn < c.enddate AND
a.SomeParameter = 'test'
GROUP BY c.startdate, c.enddate

Return All Months & Years Between Date Range - SQL

I'm a bit stumped how I might go about this.
I have a very basic query, that currently returns sales for each product, by year and month.
It is grouping by year/month, and summing up the quantity.
This returns one row for each product/year/month combo where there was a sale.
If there was no sale for a month, then there is no data.
I'd like my query to return one row of data for each product for each year/month in my date range, regardless of whether there was actually an order.
If there was no order, then I can return 0 for that product/year/month.
Below is my example query.
Declare #DateFrom datetime, #DateTo Datetime
Set #DateFrom = '2012-01-01'
set #DateTo = '2013-12-31'
select
Convert(CHAR(4),order_header.oh_datetime,120) + '/' + Convert(CHAR(2),order_header.oh_datetime,110) As YearMonth,
variant_detail.vad_variant_code,
sum(order_line_item.oli_qty_required) as 'TotalQty'
From
variant_Detail
join order_line_item on order_line_item.oli_vad_id = variant_detail.vad_id
join order_header on order_header.oh_id = order_line_item.oli_oh_id
Where
(order_header.oh_datetime between #DateFrom and #DateTo)
Group By
Convert(CHAR(4),order_header.oh_datetime,120) + '/' + Convert(CHAR(2),order_header.oh_datetime,110),
variant_detail.vad_variant_code
You can generate this by using CTE.
You will find information on this article :
http://blog.lysender.com/2010/11/sql-server-generating-date-range-with-cte/
Especially this piece of code :
WITH CTE AS
(
SELECT #start_date AS cte_start_date
UNION ALL
SELECT DATEADD(MONTH, 1, cte_start_date)
FROM CTE
WHERE DATEADD(MONTH, 1, cte_start_date) <= #end_date
)
SELECT *
FROM CTE
Thank your for your suggestions.
I managed to get this working using another method.
Declare #DateFrom datetime, #DateTo Datetime
Set #DateFrom = '2012-01-01'
set #DateTo = '2013-12-31'
select
YearMonthTbl.YearMonth,
orders.vad_variant_code,
orders.qty
From
(SELECT Convert(CHAR(4),DATEADD(MONTH, x.number, #DateFrom),120) + '/' + Convert(CHAR(2),DATEADD(MONTH, x.number, #DateFrom),110) As YearMonth
FROM master.dbo.spt_values x
WHERE x.type = 'P'
AND x.number <= DATEDIFF(MONTH, #DateFrom, #DateTo)) YearMonthTbl
left join
(select variant_Detail.vad_variant_code,
sum(order_line_item.oli_qty_required) as 'Qty',
Convert(CHAR(4),order_header.oh_datetime,120) + '/' + Convert(CHAR(2),order_header.oh_datetime,110) As 'YearMonth'
FROM order_line_item
join variant_detail on variant_detail.vad_id = order_line_item.oli_vad_id
join order_header on order_header.oh_id = order_line_item.oli_oh_id
Where
(order_header.oh_datetime between #DateFrom and #DateTo)
GROUP BY variant_Detail.vad_variant_code,
Convert(CHAR(4),order_header.oh_datetime,120) + '/' + Convert(CHAR(2),order_header.oh_datetime,110)
) as Orders on Orders.YearMonth = YearMonthTbl.YearMonth
This is what I put together. It will certainly need some debugging, but I think that this will lead you in the right direction. I broke up the queries into different parts in order to attempt to make it easier to read. Hope this helps.
DECLARE #dateFrom DATETIME, #dateTo DATETIME
SELECT #dateFrom = MIN(oh_datetime) FROM order_header
SELECT #dateTo = MAX(oh_datetime) FROM order_header
;WITH
y AS
(
SELECT YEAR(#dateFrom) AS [Year]
UNION ALL
SELECT [Year] + 1
FROM y
WHERE
[Year] < YEAR (GETDATE())
),
m AS
(
SELECT 1 AS [Month]
UNION ALL
SELECT [Month] + 1
FROM m
WHERE
[Month] < 12
),
dates AS
(
SELECT
CAST(y.[Year] AS nvarchar(4)) + N'/' + RIGHT(N'00' + CAST(m.[Month] AS nvarchar(2)), 2) AS YearMonth
FROM
y CROSS JOIN m
),
qty AS
(
SELECT
YEAR(oh.oh_datetime) + N'/' + MONTH(oh.oh_datetime) AS YearMonth,
v.vad_variant_code,
oli.oli_qty_required AS Qty
FROM
variant_Detail AS v
INNER JOIN order_line_item AS oli ON oil.oli_vad_id = v.vad_id
INNER JOIN order_header AS oh ON oh.oh_id = oli.oli_oh_id
)
SELECT
d.YearMonth,
qty.vad_variant_code,
SUM(qty.Qty) AS TotalQty
FROM
dates AS d LEFT OUTER JOIN qty
ON d.YearMonth = qty.YearMonth
GROUP BY
d.YearMonth,
qty.vad_variant_code
Here is another twist, if you find all months of a year
;WITH DateYear AS (
SELECT 0 AS num
UNION ALL
SELECT num + 1 FROM DateYear
WHERE num < 11
)
Select FirstDateOfTheMonth, DATENAME(mm,FirstDateOfTheMonth), num from
(SELECT CONVERT(DATE,DATEADD(MONTH,num,'2017')) AS FirstDateOfTheMonth, num from DateYear)
cte
and the result will be
Another twist:
Declare #dateFrom datetime ='2019-03-21', #dateTo datetime ='2019-12-31'
;WITH CTE AS
(
SELECT #dateFrom AS cte_start_date
UNION ALL
SELECT DATEADD(MONTH, 1, cte_start_date)
FROM CTE
WHERE ( DATEADD(MONTH, 1, cte_start_date) <= EOMONTH( #dateTo) )
--or ( DATENAME(MONTH, cte_start_date) =DATENAME(MONTH, #dateTo) and DATENAME(year, cte_start_date) =DATENAME(year, #dateTo) ) )
)
SELECT *
FROM CTE
This below is work for sqlserver 2012 and above to get the last day of the month :-
Select EOMONTH('2020-02-15')

Making SQL query results 'PRINT'?

I have a query which I eventually got to work fine but what I really need is the results to be displayed using the SQL PRINT command. The reason for this is I am automating the results to be emailed, and if I can have them come out as printed text then I can just embed the results in the email using the tool we use here. Otherwise, the current results have to be attached as a file and I would prefer the printed text if possible.
I have tried to modify the query by adding DECLARE and PRINT but I am really confused and can't figure it out. The query has 2 CTE's in it pulling data from multiple databases. What it is doing is selecting all the sale numbers/ID's from our SAP system for yesterday and comparing them with our the Sale numbers/ID's from our POS system for yesterday to make sure every sale in our POS system is now in SAP. The query itself works fine.
How can I print the results of this query?
WITH CTE1 (SAP_SALE)
AS
(
select distinct convert(BIGINT,convert(varchar(15),WERKS)+(select RIGHT(convert(Varchar(20),BONNR),7)))
as Branch_tx_no from [PDP].[pdp].[S120] WITH (NOLOCK)
where SPTAG >= CAST(CONVERT(VARCHAR(10), GETDATE() -1, 101) AS DATETIME) AND
SPTAG < CAST(CONVERT(VARCHAR(10), GETDATE(), 101) AS DATETIME)
),
CTE2 (AR_SALE)
AS
(
select convert(varchar(15),branch_no)+convert(varchar(15),sale_tx_no)
from [ARDB01].[PP_BODATA].[DBO].[sales_tx_hdr] WITH (NOLOCK)
WHERE sale_date >= CAST(CONVERT(VARCHAR(10), GETDATE() -1, 101) AS DATETIME) AND
sale_date < CAST(CONVERT(VARCHAR(10), GETDATE(), 101) AS DATETIME)
and sale_type in ('C','L')
)
SELECT AR_SALE FROM CTE2 AS CTE2
Left OUTER JOIN CTE1 AS CTE1
ON CTE1.SAP_SALE = CTE2.AR_SALE
WHERE CTE1.SAP_SALE IS NULL
ORDER BY CTE2.AR_SALE
The easiest solution is to use a cursor and PRINT one row at a time. Or you could use XML-concatenation, if you do not have any special characters in the result:
DECLARE #txt NVARCHAR(MAX);
WITH CTE1 (SAP_SALE)
AS
(
select distinct convert(BIGINT,convert(varchar(15),WERKS)+(select RIGHT(convert(Varchar(20),BONNR),7)))
as Branch_tx_no from [PDP].[pdp].[S120] WITH (NOLOCK)
where SPTAG >= CAST(CONVERT(VARCHAR(10), GETDATE() -1, 101) AS DATETIME) AND
SPTAG < CAST(CONVERT(VARCHAR(10), GETDATE(), 101) AS DATETIME)
),
CTE2 (AR_SALE)
AS
(
select convert(varchar(15),branch_no)+convert(varchar(15),sale_tx_no)
from [ARDB01].[PP_BODATA].[DBO].[sales_tx_hdr] WITH (NOLOCK)
WHERE sale_date >= CAST(CONVERT(VARCHAR(10), GETDATE() -1, 101) AS DATETIME) AND
sale_date < CAST(CONVERT(VARCHAR(10), GETDATE(), 101) AS DATETIME)
and sale_type in ('C','L')
)
SELECT #txt = (
SELECT CHAR(13)+CHAR(10)+AR_SALE FROM CTE2 AS CTE2
Left OUTER JOIN CTE1 AS CTE1
ON CTE1.SAP_SALE = CTE2.AR_SALE
WHERE CTE1.SAP_SALE IS NULL
ORDER BY CTE2.AR_SALE
FOR XML PATH(''),TYPE
).value('.','NVARCHAR(MAX)');
PRINT #txt;
If you need to use PRINT you can combine results of your query into a comma (or other char) separated VARCHAR variable and then print that variable, e.g.
DECLARE #sTMP varchar(1000)
SET #sTMP = ''
-- Your CTE....
SELECT #sTMP = #sTMP + AR_SALE + ',' FROM CTE2 AS CTE2
Left OUTER JOIN CTE1 AS CTE1
ON CTE1.SAP_SALE = CTE2.AR_SALE
WHERE CTE1.SAP_SALE IS NULL
ORDER BY CTE2.AR_SALE
PRINT #sTMP
WITH CTE1 (SAP_SALE)
AS
(
select distinct convert(BIGINT,convert(varchar(15),WERKS)+(select RIGHT(convert(Varchar(20),BONNR),7)))
as Branch_tx_no from [PDP].[pdp].[S120] WITH (NOLOCK)
where SPTAG >= CAST(CONVERT(VARCHAR(10), GETDATE() -1, 101) AS DATETIME) AND
SPTAG < CAST(CONVERT(VARCHAR(10), GETDATE(), 101) AS DATETIME)
),
CTE2 (AR_SALE)
AS
(
select convert(varchar(15),branch_no)+convert(varchar(15),sale_tx_no)
from [ARDB01].[PP_BODATA].[DBO].[sales_tx_hdr] WITH (NOLOCK)
WHERE sale_date >= CAST(CONVERT(VARCHAR(10), GETDATE() -1, 101) AS DATETIME) AND
sale_date < CAST(CONVERT(VARCHAR(10), GETDATE(), 101) AS DATETIME)
and sale_type in ('C','L')
)
SELECT AR_SALE, row_number() over (order by AR_SALE) as r
into #temp -- added this row right here
FROM CTE2 AS CTE2
Left OUTER JOIN CTE1 AS CTE1
ON CTE1.SAP_SALE = CTE2.AR_SALE
WHERE CTE1.SAP_SALE IS NULL
ORDER BY CTE2.AR_SALE
then...
declare #x varchar(100)
declare #i int
set #i = 1
while (#i <= (select max(r) from #temp)) begin
select #x=AR_SALE from #temp where r=#i
print #x
set #i=#i+1
end