Converting Different columns into rows in SQL Server - sql

I have data in SQL Server that needs to be converted from columns into rows. Now although this question has been asked quite a lot in sometime, I was still facing some difficulty and hence I was wondering if someone can assist me.
Currently the format is as below.
The table format that is required and that will be very helpful will be;
So not only the PIVOT needs to be applied but I am not sure which SQL Query syntax will help to identify the Type. I have tried using CASE-WHEN with PIVOT but that really yield correct output.
Regards!

You can use CROSS APPLY query like below
see working demo
Select
ProjectName,
v.*
from t
cross apply
(
values
('Plan',PlanStartDate,PlanEndDate),
('Actual',ActualStartDate, ActualEndDate)
)v(type,StartDate, EndDate)

Try this
;WITH CTE2(ProjectName,[Plan Start Date],[Plan End Date],[Actual Start Date],[Actual End Date])
AS
(
SELECT 'PR-A','1/1/2006','1/4/2006','1/4/2007','1/5/2008' UNION ALL
SELECT 'PR-B','1/1/2007','1/1/2008','4/4/2008','6/6/2008' UNION ALL
SELECT 'PR-C','1/1/2004','1/1/2008','2/5/2001','2/2/2008'
)
SELECT Projectname,
'Plan' AS [Type],
[Plan start date] AS [Start Date],
[Plan end date] AS [End Date]
FROM Cte2
UNION ALL
SELECT Projectname,
'Actual' AS [Type],
[Actual start date],
[Actual end date]
FROM Cte2
ORDER BY Projectname,
[Type] DESC
Demo :http://rextester.com/CQEBV76844

Related

New to SQL. Would like to convert an IF(COUNTIFS()) Excel formula to SQL code and have SQL calculate it instead of Excel

I am running SQL Server 2008 R2 (RTM).
I have a SQL query that pulls Dates, Products, Customers and Units:
select
[Transaction Date] as Date,
[SKU] as Product,
[Customer Name] as Customer,
sum(Qty) as Units
from dataset
where [Transaction Date] < '2019-03-01' and [Transaction Date] >= '2016-01-01'
group by [Transaction Date], [SKU], [Customer Name]
order by [Transaction Date]
This pulls hundreds of thousands of records and I wanted to determine if a certain transaction was a new order or reorder based on the following logic:
Reorder: That specific Customer has ordered that specific product in the last 6 months
New Order: That specific Customer hasn’t ordered that specific product in the last 6 months
For that I have this formula in Excel that seems to be working:
=IF(COUNTIFS(A$1:A1,">="&DATE(YEAR(A2),MONTH(A2)-6,DAY(A2)),C$1:C1,C2,B$1:B1,B2),"Reorder","New Order")
The formula works when I paste it individually or in a smaller dataset, but when I try to copy paste it to all 500K+ rows, Excel gives up because it loops for each calculation.
This could probably be done in SQL, but I don’t have the knowledge on how to convert this excel formula to SQL, I just started studying it.
You're doing pretty well with the start of your query there. There are three additional functions you're looking to add to your query.
The first thing you'll need is the easiest. GETDATE() simply returns the current date. You'll need that when you're comparing the current date to the transaction date.
The second function is DATEDIFF, which will give you a unit of time between two dates (months, days, years, quarters, etc). Using DATEDIFF, you can say "is this date within the last 6 months". The format for this is pretty easy. It's DATEDIFF(interval, date1, date2).
The thrid function you're looking for is CASE, which allows you to tell SQL to give you one answer if one condition is met, but a different answer if a different condition is met. For your example, you can say "if the difference in days is < 60, return 'Reorder', if not give me 'New Order'".
Putting it all together:
SELECT CASE
WHEN DATEDIFF(MONTH, [Transaction Date], GETDATE()) <= 6
THEN 'Reorder'
ELSE 'New Order'
END as ORDER_TYPE
,[Transaction Date] AS DATE
,[SKU] AS PRODUCT
,[Customer Name] AS CUSTOMER
,Qty AS UNITS
FROM DATASET
For additonal examples on CASE, take a look at this site: https://www.w3schools.com/sql/sql_ref_case.asp
For additional examples on DATEDIFF, take a look here: See the
following webpage for examples and a chance to try it out:
https://www.w3schools.com/sql/func_sqlserver_datediff.asp
SELECT CASE
WHEN Datediff(day, [transaction date], Getdate()) <= 180 THEN 'reorder'
ELSE 'Neworder'
END,
[transaction date] AS Date,
[sku] AS Product,
[customer name] AS Customer,
qty AS Units
FROM datase
If I understand correctly, you want to peak at the previous date and make a comparison. This suggests lag():
select (case when lag([Transaction Date]) over (partition by SKU, [Customer Name] order by [Transaction Date]) >
dateadd(month, -6, [Transaction Date])
then 'Reorder'
else 'New Order'
end) as Order_Type
[Transaction Date] as Date,
[SKU] as Product,
[Customer Name] as Customer,
sum(Qty) as Units
from dataset d
group by [Transaction Date], [SKU], [Customer Name];
EDIT:
In SQL Server 2008, you can emulate the LAG() using OUTER APPLY:
select (case when dprev.[Transaction Date] >
dateadd(month, -6, d.[Transaction Date])
then 'Reorder'
else 'New Order'
end) as Order_Type
d.[Transaction Date] as Date,
d.[SKU] as Product,
d.[Customer Name] as Customer,
sum(d.Qty) as Units
from dataset d outer apply
(select top (1) dprev.*
from dataset dprev
where dprev.SKU = d.SKU and
dprev.[Customer Name] = d.[Customer Name] and
dprev.[Transaction Date] < d.[Transaction Date]
order by dprev.[Transaction Date] desc
) dprev
group by d.[Transaction Date], d.[SKU], d.[Customer Name];

Between Dates Query

I had a question up earlier and it was pretty much solved expect one part of it. for some reason its not showing me between dates for my query. Just the dates that i enter in the parameter. i was wondering if anyone can see any problem with the code. Any help is much appreciated.
Relationships
SELECT *
FROM Vehicles
WHERE Vehicles.vehicle_id NOT IN (
SELECT Booking.[vehicle id]
FROM Booking
WHERE (
[Enter Start Date] BETWEEN booking.start_rent_date
AND booking.end_rent_date
)
OR (
[Enter End Date] BETWEEN booking.start_rent_date
AND booking.end_rent_date
)
);
It's supposed that [Enter End Date] is greater than [Enter Start Date].
First, try if this single query works fine:
SELECT Booking.*
FROM Booking
WHERE (((Booking.start_rent_date)>#2016/11/1#)
AND ((Booking.end_rent_date)<#2016/11/20#));
Second, try to join with distinct values:
SELECT *
FROM Vehicles
WHERE Vehicles.vehicle_id NOT IN
(
SELECT distinct Booking.[vehicle id]
FROM Booking
WHERE (((Booking.start_rent_date)>#2016/11/1#)
AND ((Booking.end_rent_date)<#2016/11/20#))
);

Extract a specific line from a SELECT statement based on the last Trasanction date

Good day,
I have an SQL code that return to me all quantities that I received over time, but I want to display only the latest one
SELECT * FROM
(SELECT DISTINCT
[dbo].[ttcibd001110].[t_cmnf] AS [Manufacturer],
[dbo].[ttcibd001110].[t_item] AS [Item code],
[dbo].[ttcibd001110].[t_dsca] AS [Description],
[dbo].[ttcibd001110].[t_seak] AS [Search key 1],
[dbo].[twhinr110110].[t_trdt] AS [Transaction date],
[dbo].[twhinr110110].[t_cwar] AS [Warehouse],
[dbo].[twhinr110110].[t_qstk] AS [Quantity Inventory Unit]
FROM [dbo].[twhinr110110] LEFT JOIN [dbo].[ttcibd001110]
ON [dbo].[twhinr110110].[t_item]=[dbo].[ttcibd001110].[t_item]
WHERE [dbo].[twhinr110110].[t_koor]='2' AND [dbo].[ttcibd001110].[t_cmnf]='ManufacturerX') AS tabel
WHERE ltrim(tabel.[Item code])='1000045'
Now, from this selection I want to select only the line with the latest Transaction date, but I am stuck.
Can somebody help me in this way?
Thank you!
Change your beginning to
SELECT TOP 1
and after where use
ORDER BY [Transaction date] DESC

Scripting the latest month in the data set [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
In the following view,instead of specifying the actual dates in the where condition,I want sql server to recognize June and May as the latest month and the (latest month-1) as the view gets refreshed on a monthly basis and so does latest month and (latest month -1).
PS:- The latest Report month is June in the table
SELECT (A.[First Name])
,A.[Last Name]
,A.[Report Month]
FROM (
(
SELECT DISTINCT [First Name]
,[Last Name]
,[Report Month]
,[Bill To Code]
,[Region]
,[Area]
FROM dbo.Data
WHERE (
[Report Month] BETWEEN '2015-06-01'
AND '2015-06-30'
AND [FTE Status] = 'Inactive'
)
) A INNER JOIN (
SELECT DISTINCT [First Name]
,[Last Name]
,[Report Month]
,[Bill To Code]
,[Region]
,[Area]
FROM dbo.Data
WHERE (
[Report Month] BETWEEN '2015-05-01'
AND '2015-05-31'
AND [FTE Status] = 'Active'
)
) B ON A.[First Name] = B.[First Name]
AND A.[Last Name] = B.[Last Name]
)
Thank you,just learnt how to format better in SO.Thanks to Sean.Learning from my mistakes guys..:)
Hence i should write some function so that sql server reads the start
and end date of the latest month in the data set.
You say you need to read the start and end date, but if what you really need is just to get all the data that is in the latest month in your table, then this will do it:
select *
from dbo.Data
where DATEDIFF(month,[Report Month],(SELECT MAX([Report Month] FROM dbo.Data))=0
and [FTE Status]='Active'
Despite your rather vague question, I think this is what you are looking for.
This will return the first and last day for the max date in YourTable.
;with cte as (
select convert(date,left(convert(varchar,Max(Report_Month),112),6) + '01') startDate,
month(Max(Report_Month)) n
from YourTable
union all
select dateadd(month,n,convert(date,convert(varchar,year(startDate)) + '0101')) startDate,
(n+1) n
from cte
where n < month(startDate)
)
select startdate, dateadd(day,-1,dateadd(month,1,startdate)) enddate
from cte
How about:
SELECT MAX(MONTH(Report_Month))
FROM YourTable
GROUP BY YEAR(Report_Month)
HAVING YEAR(Report_Month) = MAX(YEAR(Report_Month))

sql distinct with multiple fields requried

I'm using Advantage Database Server by Sybase. I need to elimiate duplicate addbatch's from my report, but having trouble pulling up just distinct records. Any idea what I am missing?
here is what I am using
SELECT DISTINCT
SI.[addbatch] as [Batch#],
SI.[current account #] as [Account],
SI.[status date] as [Status Date],
SI.[SKU] as [SKU],
AC.[email address] as [Email]
FROM salesinventory SI, accounts AC
WHERE AC.[account #]=SI.[current account #] and [Status Date] > '6/1/2015'
I still get duplicate addbatch's though. I'm not sure where I am going wrong! Thanks in advance! Wasn't even sure how to google this question!
The problem is that you need to check uniqueness of a single column and that's not actually what your code is performing. Try this
SELECT *
FROM (SELECT SI.[addbatch] as [Batch#],
SI.[current account #] as [Account],
SI.[status date] as [Status Date],
ETC,
ROW_NUMBER() OVER (PARTITION BY [Batch#]) AS RowNumber
FROM salesinventory SI, accounts AC
WHERE AC.[account #]=SI.[current account #] and [Status Date] > '6/1/2015') as rec
WHERE rec.RowNumber = 1
-- The following code is generic to de-duplicate records, modify to suit your need.
select x.[Well_Name] as nameX
, x.[TestDate] as dateX
from (
SELECT count(*) as dup
,[Well_Name]
,[TestDate]enter code here
FROM [dbo].[WellTests]
group by [TestDate] ,[Well_Name] ) x
where dup > 1
If you want to have unique batch numbers in your result, you have to GROUP BY the batch field only.
Something like this should work:
SELECT
SI.[addbatch] as [Batch#],
MIN(SI.[current account #]) as [Account],
MIN(SI.[status date]) as [Status Date],
MIN(SI.[SKU]) as [SKU],
MIN(AC.[email address]) as [Email]
FROM salesinventory SI, accounts AC
WHERE AC.[account #]=SI.[current account #] and [Status Date] > '6/1/2015'
GROUP BY
SI.[addbatch]
You didn't say how you want to aggregate the other columns, just replace MIN with something that makes more sense for you, like SUM or COUNT, etc.
There is a topic about grouping in the documentation.
PS: SELECT DISTINCT is (basically) just a shorter way to GROUP BY on all columns without any aggregation.