Date Conversion in SQL Server? - sql

I have a query that generates this table:
DateCompleted
GtrReference
SourceWarehouse
TargetWarehouse
DateCreated
EntryType
ControlAccount
InitialValue
Operator
FirstDesc
SecondDesc
202302
01062023
W
01
2023-01-06 00:00:00.000
W
1610
6080.00
CWHITE
IN TRANSIT WAREHOUSE
MAIN WAREHOUSE
202302
01172023
W
01
2023-01-17 00:00:00.000
W
1610
6210.00
CWHITE
IN TRANSIT WAREHOUSE
MAIN WAREHOUSE
202302
02022023
W
01
2023-02-02 00:00:00.000
W
1610
3616.00
CWHITE
IN TRANSIT WAREHOUSE
MAIN WAREHOUSE
The Query:
select
DateCompleted,
GtrReference,
SourceWarehouse,
TargetWarehouse,
DateCreated,
EntryType,
ControlAccount,
InitialValue,
Operator,
FirstDesc,
SecondDesc
from
(
select
concat(d.TransfCompYear, case when len(d.TransfCompPeriod) = 1 then '0' end, d.TransfCompPeriod) as DateCompleted,
a.Complete,
d.Line,
d.TransfCompPeriod as DateMonth,
d.TransfCompYear as DateYear,
a.GtrReference as GtrReference,
a.SourceWarehouse as SourceWarehouse,
max(a.TargetWarehouse) over (partition by a.GtrReference) as TargetWarehouse,
a.DateCreated as DateCreated,
COALESCE(d.ExpectedDueDate, d.ExpectedDueDate) as ExpectedDueDate,
a.EntryType as EntryType,
a.ControlAccount as ControlAccount,
max(a.InitialValue) over (partition by a.GtrReference) as InitialValue,
a.Operator as Operator,
b.Description as FirstDesc,
c.Description as SecondDesc
FROM
[GtrMaster] a
LEFT JOIN [InvWhControl] b
ON (a.SourceWarehouse = b.Warehouse)
LEFT JOIN [InvWhControl] c
ON (a.TargetWarehouse = c.Warehouse)
LEFT JOIN [GtrDetail] d
ON (a.GtrReference = d.GtrReference)
) as i
WHERE ( i.EntryType = 'W' OR i.EntryType = 'S' )
AND i.Complete = 'Y' AND i.GtrReference >= ''
and i.Line = '1'
and i.DateCompleted >= convert(varchar(6),getdate()-90,112)
ORDER BY i.DateCompleted desc
What i'm trying to do is change the DateCompleted column to show an actual date.
Ex, I want to change 202302 to show 2023-02-01, and 202301 to show 2023-01-01. How can I convert my current date column to that?

Use Convert:
Convert(DateTime, [DateCompleted] + '01') As TrueDateCompleted
The returned date values you can format as you like.

A calendar table would be very useful here.
From a calendar table you could CONCAT() the year and month columns for each date (or use a YearMonthNum column). Then join this column to your DateCompleted column, returning only the first date of each month via some distinction clause e.g., WHERE DayNum = 1

Related

How to combine a query with an INNER JOIN to a subquery containing a RANK function?

I have a query A that returns basic stats by using an INNER JOIN on two tables (sites & data) and calculating min, max, count, etc. I also have a query B that retrieves the latest value from a single table (data).
But I'm attempting to join the two queries so that I can display latest value along with the min, max, count values. I've tried basic unions but I think I'm missing something.
Query A:
SELECT
xc_data1.station_id,
xc_data1.sensorname,
xc_sites.site_comment,
xc_sites.SITE_LONG_NAME,
xc_sites.IPADDRESS,
COUNT(xc_data1.time_tag) AS result_count,
MIN(xc_data1.time_tag) AS start_time,
MAX(xc_data1.time_tag) AS last_time
FROM
[XC_DATA].[dbo].[xc_sites]
INNER JOIN
[XC_DATA].[dbo].[xc_data1] ON xc_sites.station_id = xc_data1.station_id
WHERE
time_tag > DATEADD(day, -7, GETDATE())
GROUP BY
xc_data1.station_id, xc_data1.sensorname,
xc_sites.site_comment, xc_sites.SITE_LONG_NAME, xc_sites.IPADDRESS
ORDER BY
last_time desc
Query B:
SELECT
station_id,
sensorname,
time_tag,
orig_value AS Last_record
FROM
(SELECT
station_id, sensorname, time_tag, orig_value,
RANK() OVER (PARTITION BY station_id ORDER BY time_tag DESC) AS rk
FROM
[XC_DATA].[dbo].[xc_data1]) t
WHERE
rk = 1
AND time_tag > DATEADD(day, -30, GETDATE())
ORDER BY
time_tag DESC
Result of query A:
station_id
sensorname
site_comment
SITE_LONG_NAME
IPADDRESS
result_count
start_time
last_time
011370
RAIN
marshy
Dead Marshes
10.123.192.6
2062
7/14/2022 11:00
7/21/2022 14:55
011369
RAIN
sandy
Hobbit Hole
10.123.192.56
2061
7/14/2022 11:00
7/21/2022 14:55
Result of query B:
station_id
sensorname
time_tag
Last_record
011370
RAIN
7/21/2022 14:55
0.01
011369
RAIN
7/21/2022 14:55
0.05
Desired result:
station_id
sensorname
site_comment
SITE_LONG_NAME
IPADDRESS
result_count
Last_Record
start_time
last_time
011370
RAIN
marshy
Dead Marshes
10.123.192.6
2062
0.01
7/14/2022 11:00
7/21/2022 14:55
011369
RAIN
sandy
Hobbit Hole
10.123.192.56
2061
0.05
7/14/2022 11:00
7/21/2022 14:55
Use a CTE
With QueryA as
(SELECT xc_data1.station_id,
xc_data1.sensorname,
xc_sites.site_comment,
xc_sites.SITE_LONG_NAME,
xc_sites.IPADDRESS,
count(xc_data1.time_tag) as result_count,
min(xc_data1.time_tag) as start_time,
max(xc_data1.time_tag) as last_time
FROM [XC_DATA].[dbo].[xc_sites] INNER JOIN [XC_DATA].[dbo].[xc_data1] ON xc_sites.station_id = xc_data1.station_id
where time_tag > DATEADD(day, -7, GETDATE())
GROUP BY xc_data1.station_id, xc_data1.sensorname,xc_sites.site_comment, xc_sites.SITE_LONG_NAME, xc_sites.IPADDRESS
order by last_time desc
),
QueryB as
(
SELECT station_id,
sensorname,
time_tag,
orig_value as Last_record
FROM (SELECT station_id, sensorname, time_tag, orig_value,
RANK() OVER (PARTITION BY station_id ORDER BY time_tag DESC) AS rk
FROM [XC_DATA].[dbo].[xc_data1]) t
WHERE rk = 1 and time_tag > DATEADD(day, -30, GETDATE())
ORDER BY time_tag desc
)
Select *
From QueryA A
Join QueryB B on A.station_id = B.station_id and A.sensorname = B.sensorname

SQL: How to get Max Order number row from multiple rows

How can I Select Max Order_number row from given multiple rows? per example below results 9010305604 is the max number. I need to select 9010305604row
SELECT DISTINCT
CUST.PRIMARY_EMAIL_ADDRESS [EMAIL],
OD.ORDER_NO [ORDER_NUMBER],
CUST.MASTER_CUSTOMER_ID [CUSTOMER ID],
CUST.SUB_CUSTOMER_ID,
CUST.USR_ORIG_JOIN_DATE,
OD.CYCLE_END_DATE
, OD.RATE_CODE
,OD.CYCLE_BEGIN_DATE
--, OD.ORIGINAL_ORDER_NO
FROM CUSTOMER CUST (NOLOCK)
INNER JOIN ORDER_DETAIL OD (NOLOCK)
ON CUST.MASTER_CUSTOMER_ID = OD.SHIP_MASTER_CUSTOMER_ID
AND OD.SHIP_SUB_CUSTOMER_ID = CUST.SUB_CUSTOMER_ID
INNER JOIN ORDER_MASTER OM (NOLOCK)
ON OD.ORDER_NO = OM.ORDER_NO
INNER JOIN PRODUCT PROD
ON [PROD].[PRODUCT_ID] = [OD].[PRODUCT_ID]
WHERE OD.SUBSYSTEM = 'MBR'
AND OD.PRODUCT_CODE IN ('PROFESSIONAL')
AND OD.LINE_STATUS_CODE = 'A'
-- AND OD.CYCLE_BEGIN_DATE <= GETDATE()
AND OD.CYCLE_END_DATE >= GETDATE()
--AND OD.ORIGINAL_ORDER_NO IS NULL
AND CUST.PRIMARY_EMAIL_ADDRESS IS NOT NULL
AND CUST.USR_ORIG_JOIN_DATE >cast(DATEADD(day, -120,GETDATE()) AS DATE)
AND OM.USR_BULK_ORDER_NO IS NULL
AND MASTER_CUSTOMER_ID = '4655302'
EMAIL ORDER_NUMBER CUSTOMER ID SUB_CUSTOMER_ID USR_ORIG_JOIN_DATE CYCLE_END_DATE RATE_CODE CYCLE_BEGIN_DATE
sannyastari#gmail.com 9010305603 4655302 0 2020-11-21 00:00:00.000 2020-12-31 00:00:00.000 1YR 2020-11-21 00:00:00.000
sannyastari#gmail.com 9010305604 4655302 0 2020-11-21 00:00:00.000 2021-12-31 00:00:00.000 1YR 2021-01-01 00:00:00.000
Use a TOP query?
SELECT DISTINCT TOP 1
CUST.PRIMARY_EMAIL_ADDRESS [EMAIL],
OD.ORDER_NO [ORDER_NUMBER],
...
(rest of your query)
ORDER BY
OD.ORDER_NO DESC;

SQL left join same column and table

I have a customer order data and would like to do analysis on customer retention after price changes.
The order table is as follows:
customer_id order_number order_delivered_date
14156 R980193622 2/6/2020 14:51
1926396 R130222714 22/5/2020 11:02
1085123 R313065343 22/5/2020 14:50
699858 R693959049 8/6/2020 17:03
1609769 R195969327 3/6/2020 16:14
14156 R997103187 27/6/2020 14:01
1926396 R403942827 11/6/2020 14:42
1926396 R895013611 8/7/2020 17:04
So, I would like to pull order in the period before new price. Assume the new price implementation is on 10/6/2020. I would like to do left join to order after the new price on the customer_id.
Before is a set of data dated 10/5/2020 00:00:00 to 9/6/2020 23:59:59 while After is a set of data dated 10/6/2020 00:00:00 to 9/7/2020 23:59:59.
The desired table:
Before After
14156 14156
1926396 1926396
1085123 Null
699858 Null
1609769 Null
If customer_id is found side by side it means they are retained. It should be simple...But I have been stucked.
EDIT:
This is few code that I have been trying
First try:
select ol2.customer_id as before, ol.customer_id as after
from master.order_level ol,
left join master.order_level ol2
on ol2.customer_id = ol.customer_id
where order_delivered_date between '2020-05-10 00:00:00' and '2020-07-09 23:59:59' and country_id = 2
Second try:
SELECT ol.customer_id as before, ol2.customer_id as after
FROM master.order_level ol,master.order_level ol2
left join master.order_level
ON ol.customer_id = ol2.customer_id
WHERE ol.order_delivered_date between '2020-05-10 00:00:00' and '2020-06-09 23:59:59' and ol.country_id =2 and ol2.order_delivered_date between '2020-06-10 00:00:00' and '2020-07-09 23:59:59' and ol2.country_id =2
No need to do a join, you can just use you can do a simple group by and use case and aggregate functions. I also made a fiddle showing it in action here
SELECT customer_id,
CASE
WHEN MIN(order_delivered_date) < '3-15-2019' THEN customer_id
ELSE NULL END customer_before,
CASE
WHEN MAX(order_delivered_date) >= '3-15-2019' THEN customer_id
ELSE NULL END customer_after
FROM my_table
GROUP BY customer_id
there qyery will giva you results like this
customer_id customer_before customer_after
4 4 (null)
1 1 1
3 3 (null)
2 2 2
with before (customer_id) as
( select distinct customer_id from orders where order_delivered_date <= '10/06/2020'
),
after (customer_id) as
(select distinct customer_id from orders where order_delivered_date between '10/06/2020' and '09/07/2020')
select
before.customer_id,
after.customer_id
from before left outer join after on before.customer_id = after.customer_id
you can use union
select customer_id as before, null as after
from #order
where order_delivered_date <'2020-06-10'
union
select null as before, customer_id as after
from #order
where order_delivered_date >='2020-06-10'
results

How can I get distinct data from one col

I need to get member personal data for all our members whose subscriptions have lapsed i.e. have a subscription end date before 31/03/2020, however I want to show one member record only (distinct by membership number) ideally the most recent one
I've tried a ROW_NUMBER() solution SQL - Distinct One Col, Select Multiple other? and a cross apply solution sql distinct, getting 2 columns but I can't get it to work.
SELECT membershipnumber AS Id,
subscription.enddate
FROM [dbo].[userprofile]
INNER JOIN dbo.subscription
ON userprofile.id = subscription.userprofileid
INNER JOIN dbo.subscriptiontype
ON subscriptiontype.id = subscription.subscriptiontypeid
Output is
Id Enddate
1 2006-04-01 00:00:00.000
1 2001-04-01 00:00:00.000
1 1999-04-01 00:00:00.000
1 1998-04-01 00:00:00.000
1 2008-04-01 00:00:00.000
1 2007-04-01 00:00:00.000
1 2011-04-01 00:00:00.000
1 2005-04-01 00:00:00.000
1 2000-04-01 00:00:00.000
1 1997-04-01 00:00:00.000
2 1999-04-01 00:00:00.000
2 2012-04-01 00:00:00.000
2 2004-04-01 00:00:00.000
2 2001-04-01 00:00:00.000
2 2018-04-01 00:00:00.000
2 2009-04-01 00:00:00.000
2 2005-04-01 00:00:00.000
2 1997-04-01 00:00:00.000
Desired output
Id Enddate
1 2011-04-01 00:00:00.000
2 2018-04-01 00:00:00.000
Solved sql answer
;WITH cte
AS (SELECT membershipnumber AS Id,
subscription.enddate,
Row_number()
OVER (
partition BY membershipnumber
ORDER BY subscription.enddate DESC) AS rownumber
FROM [dbo].[userprofile]
INNER JOIN dbo.subscription
ON userprofile.id = subscription.userprofileid
INNER JOIN dbo.subscriptiontype
ON subscriptiontype.id = subscription.subscriptiontypeid
)
SELECT *
FROM cte
WHERE rownumber = 1
https://stackoverflow.com/a/6841644/5859743
Not sure if I got your question right.
but you can use DISTINCT in the SELECT, that would show only one record for each member.
SELECT DISTINCT Membershipnumber as Id
,'P' as PartyType
,'A' as Status
,case
when Name = 'Standard Membership paid annually.' and EndDate > '2020-03-31' then 'Member'
when Name = 'Lapsed subscription renewal' and EndDate > '2020-03-31' then 'Member'
when Name = '3 Year Subscription (members outside of UK and Ireland, Jersey, Guernsey and the Channel Islands)' and EndDate > '2020-03-31' then 'Overseas member'
when Name = '1 Year Subscription (members outside of UK and Ireland, Jersey, Guernsey and the Channel Islands).' and EndDate > '2020-03-31' then 'Overseas member'
when Name = 'Lapsed subscription renewal' and EndDate > '2020-03-31' then 'Member'
when Name = 'Lifetime membership' then 'Lifetime member'
when Name = 'Retired membership paid annually' and EndDate > '2020-03-31' then 'Retired member'
else 'Non member'
end As MemberType
,Title as NamePrefix
,FirstName as FirstName
,Surname as LastName
,DateOfBirth as BirthDate
,'Home' as AddressPurpose
,'Default' as CommunicationReasons
,AddressLine1
,AddressLine2
,AddressLine3
,Addressline4 as CityName
,'' as CountrySubEntityName
,Country as CountryCode
,'' as CountryName
,Postcode as PostalCode
,EmailAddress as Email
FROM [dbo].[UserProfile]
inner join dbo.Subscription on
UserProfile.Id = Subscription.UserProfileId
inner join dbo.SubscriptionType on
SubscriptionType.id = Subscription.SubscriptionTypeId```
If you are getting as above mentioned output. Then from that, your desired output will easily get using distinct.
; with cte as (
----- query which gives you above mentioned output
)
select distinct id, max(Enddate) as Enddate from cte
I suspect you want something like this:
select *
from (select . . ., -- all the columns you want
row_number() over (partition by Membershipnumber as Id order by s.Enddate) as seqnum
from [dbo].[UserProfile] up inner join
dbo.Subscription s
on up.Id = s.UserProfileId inner join
dbo.SubscriptionType st
on st.id = s.SubscriptionTypeId
) x
where seqnum = 1;

MS SQL Server 2005 GROUP BY and SUM

Hey all, i am trying to create a report to show how much is spent per HRCode. This is my SQL Query so far:
SELECT *
FROM tblWO as WO,
tblWOD as WOD,
tblWA as WA
WHERE WOD.OrderID = WO.ID
AND WA.HRCode = WO.AdministratorCode
AND WO.OrderDate BETWEEN '2010-01-01' AND '2010-08-31'
AND Approved = '1'
ORDER BY WO.OrderDate
I'm trying to fingure out a way that mash all the same HRCode's together and then SUM() each... But my brain is not working today so i need some help :o)
Here is what the database data looks like:
ID Total OrderDate Approved HRCode AdministratorCode OrderID
3272 25.00 2010-01-04 10:48:57.617 1 RN RN 3272
4621 25.00 2010-02-04 11:15:01.600 1 RN RN 4621
4899 50.00 2010-02-04 11:55:01.630 1 02 02 4899
4905 15.00 2010-05-04 11:55:01.190 1 NR NR 4905
5001 50.00 2010-06-04 04:11:55.295 1 RN RN 5001
Any help would be great! Thanks!
SOLVED
SELECT SUM(Total) as Total, AdministratorCode
FROM tblWO as WO,
tblWOD as WOD
WHERE WOD.OrderID = WO.ID
AND WO.OrderDate BETWEEN '2010-01-01' AND '2010-08-31'
AND Approved = '1'
ORDER BY WO.AdministratorCode
David
Remove the OrderDate and ID columns from your select statement:
SELECT SUM(Total) as Total, HRCode
FROM tblWO as WO,
tblWOD as WOD,
tblWA as WA
WHERE WOD.OrderID = WO.ID
AND WA.HRCode = WO.AdministratorCode
AND WO.OrderDate BETWEEN '2010-01-01' AND '2010-08-31'
AND Approved = '1'
GROUP BY HRCode