Getting 2 result columns from SQL query - sql

I've tried to make an SQL query to get 2 result columns from 1 query. To elaborate:
This is my query:
SELECT Name, AVG(DATEDIFF(day,[Open Date],[Close Date]))
FROM Inventory Where Tested ='Yes' AND [Close Date] IS NOT NULL AND [Open Date] IS NOT NULL
GROUP BY Name
My result:
My desired result:
When also Where Tested = 'No'
How to write an SQL query with Where Tested = 'Yes' and Where Tested = 'No'? Where Tested = 'Yes' is Column 1 result and Tested = 'No' is Column 2 result.
Database:SQL server 2019

EJC answer with subqueries should already probably help with what you need, but just wanted to share some other options to achieve this:
Joining two separate queries
SELECT tested.Name, tested.TestedAVG, not_tested.NotTestedAVG FROM
(SELECT Name, AVG(DATEDIFF(day,[Open Date],[Close Date])) as "TestedAVG"
FROM Inventory
WHERE Tested ='Yes' AND [Close Date] IS NOT NULL AND [Open Date] IS NOT NULL
GROUP BY Name) tested
FULL JOIN
(SELECT Name, AVG(DATEDIFF(day,[Open Date],[Close Date])) as "NotTestedAVG"
FROM Inventory
WHERE Tested ='No' AND [Close Date] IS NOT NULL AND [Open Date] IS NOT NULL
GROUP BY Name) not_tested
ON tested.Name = not_tested.Name
Using case
SELECT Name,
AVG(CASE WHEN Tested ='Yes' THEN DATEDIFF(day,[Open Date],[Close Date]) END) as [Tested AVG],
AVG(CASE WHEN Tested ='No' THEN DATEDIFF(day,[Open Date],[Close Date]) END) as [Not Tested AVG]
FROM Inventory
WHERE [Close Date] IS NOT NULL AND [Open Date] IS NOT NULL
GROUP BY Name
Adding as group by
If you don't need to have it as a separate column, the easiest way would be to add a group by the Tested column as well.
SELECT Name, AVG(DATEDIFF(day,[Open Date],[Close Date])) as "AVG"
FROM Inventory
WHERE [Close Date] IS NOT NULL AND [Open Date] IS NOT NULL
GROUP BY Name, Tested
Then you'll get this structure:
Name
Tested
AVG
aTPO
Yes
56
aTPO
No
50

It's hard to say exactly what you want, but maybe you could use a couple of subqueries?
SELECT Name,
AVG(select DATEDIFF(i2.day,i2.[Open Date],i2.[Close Date]) from inventory i2 where i2.name = i.name and i2.Tested = 'Yes') as "Tested",
AVG(select DATEDIFF(i3.day,i3.[Open Date],i3.[Close Date]) from inventory i3 where i3.name = i.name and i3.Tested = 'No') as "Not Tested"
FROM Inventory i
Where [Close Date] IS NOT NULL AND [Open Date] IS NOT NULL
GROUP BY Name

Out of three columns if you trying to get two columns with its values, you have to specify those columns in your code.
Example:
SELECT column1, column2
FROM table_name
But if you want to find all the columns
Example:
SELECT * FROM table_name

Related

SQL create column for every week (Loop?)

I need to make a report for weekly changes.
This is the code for todays amount
SELECT
[Entry No_],
[Customer No_],
[Posting Date],
[Description],
[Currency Code],
Trans_type = case when [Deposit]=1 then 'Deposit'
when [Imprest]=1 then 'Imprest'
else 'Other' end,
A.Amount
FROM Table1
LEFT JOIN
(
SELECT Distinct [Cust_ Ledger Entry No_],
SUM ([Amount EUR]) as 'amount'
FROM Table2
group by [Cust_ Ledger Entry No_]
having
SUM ([Amount EUR]) <> '0'
)A
on [Entry No_] = A.[Cust_ Ledger Entry No_]
Where
A.Amount is not NULL
Code to generate data for previous week is here (adding only where clause):
SELECT
[Entry No_],
[Customer No_],
[Posting Date],
[Description],
[Currency Code],
Trans_type = case when [Deposit]=1 then 'Deposit'
when [Imprest]=1 then 'Imprest'
else 'Other' end,
A.Amount
FROM Table1
LEFT JOIN
(
SELECT Distinct [Cust_ Ledger Entry No_],
SUM ([Amount EUR]) as 'amount'
FROM Table2
where [posting Date] < '2020-11-23'
group by [Cust_ Ledger Entry No_]
having
SUM ([Amount EUR]) <> '0'
)A
on [Entry No_] = A.[Cust_ Ledger Entry No_]
Where
A.Amount is not NULL
It would be enough to union both queries and then export to Excel and make pivot, but problem is that I need results of last 50 weeks. Is there any smart way to avoid union 50 tables and run one simple code to generate weekly report?
Thanks
it might be easier with sample, but I don't know how to paste table here..
Maybe it is true, i dont need union here, and group by would be enough, but it stills sounds difficult for me :)
Ok. Lets say table has such headers: Project | Country | date | amount
The code below returns amount for todays date
Select
Project,
SUM(amount)
From Table
Group by Project
I actually need todays date and also the results of previous weeks (What was the result on November 22 (week 47), November 15 (week 46) and so on.. total 50 weeks from todays date).
Code for previous week amount is here:
Select
Project,
SUM(amount)
From Table
Where Date < '2020.11.23'
Group by Project
So my idea was to create create 50 codes and join the results together, but i am sure it is a better way to do this. Besides i dont want to edit this query every week and add a new date for it.
So any ideas, to make my life easier?
if I have understood your requirement correctly, all you need to do is extract the week from the date e.g.
Select
Project,
datepart(week, date),
SUM(amount)
From Table
Where Date < '2020.11.23'
Group by Project, datepart(week, date)

How to select max date over the year function

I am trying to select the max date over the year, but it is not working. Any ideas on what to do?
SELECT a.tkinit [TK ID],
YEAR(a.tkeffdate) [Rate Year],
max(a.tkeffdate) [Max Date],
tkrt03 [Standard Rate]
FROM stageElite.dbo.timerate a
join stageElite.dbo.timekeep b ON b.tkinit = a.tkinit
WHERE a.tkinit = '02672'
and tkeffdate BETWEEN '2014-01-01' and '12-31-2014'
GROUP BY a.tkinit,
tkrt03,
a.tkeffdate
Perhaps you only want it by year and not rolled up by calendar date. For SQL server you can try this.
SELECT
…
MaxDate = MAX(a.tkeffdate) OVER (PARTITION BY a.tkinit, YEAR(a.tkeffdate)))
…
Or you could modify the query above to group by the year instead of date-->
GROUP BY a.tkinit,
tkrt03,
YEAR(a.tkeffdate)
You seem to want only one row and all the columns. Use ORDER BY and TOP:
SELECT TOP (1) tr.tkinit as [TK ID],
YEAR(tr.tkeffdate) as [Rate Year],
a.tkeffdate as [Max Date],
tkrt03 as [Standard Rate]
FROM stageElite.dbo.timerate tr JOIN
stageElite.dbo.timekeep tk
ON tk.tkinit = tr.tkinit
WHERE tr.tkinit = '02672' AND
tr.tkeffdate >= '2014-01-01' AND
tr.tkeffdate < '2015-01-01'
ORDER tr.tkeffdate DESC;
Note that I also fixed your date comparisons and table aliases.

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];

SQL IF type logic help requested

I have a SQL problem that I have been stuck on for days. So this is the context. I work for a company where employees have timesheets. Each timesheet has an ID but it is not unique because it is possible for an employee to have 2 timesheets for the same ID. The difference is that normally when you submit the sheet your status is ‘Posted’. But, sometimes people screw up their entries and it has to get re-submitted with changes. Therefore, the status ‘Adjusted’.
The logic I need is the following
-Where timesheet ID’s only have one value (count=1) always use ‘Posted’ status. If there is only one value but it is not ‘Posted’ return an error string saying ‘Error’.
-where timesheet IDs have more than one value and BOTH ‘Posted’ and ‘Adjusted’ show up as status always default to ‘Adjusted’. BOTH posted and adjusted must be present in this.
I have tried case and subquery but no luck. I also have a column ‘timesheet post date’ and logic is earliest date is always posted and later date is ‘adjusted’, but in some cases the posting dates are identical.
so as you can see, I need to look at the duplicate count in one column, and then choose the value if that count is >1 from another column.
SELECT t1.[Resource NUID]
,t1.[Timesheet ID]
,t1.[Timesheet Start Date]
,t1.[Timesheet End Date]
,t1.[Timesheet Posted Date]
,t1.[Timesheet Status]
,t1.[RunSourceID]
,t1.[SpanStartDate]
,t1.[SpanEndDate]
FROM [TIME_DW].[dbo].[Timecard_Timesheets] as t1, [TIME_DW].[dbo]. [Timecard_Timesheets] as t2
where t1.[Timesheet ID]=t2.[Timesheet ID]
and t1.[Resource NUID]='e066308' and t1.[Timesheet Status]<>'Open' and t1.[Timesheet Status]<>'Submitted'
group by
t1.[Resource NUID]
,t1.[Timesheet ID]
,t1.[Timesheet Start Date]
,t1.[Timesheet End Date]
,t1.[Timesheet Posted Date]
,t1.[Timesheet Status]
,t1.[RunSourceID]
,t1.[SpanStartDate]
,t1.[SpanEndDate]
order by t1.[Timesheet Start Date] asc
this is an example of an actual record that has two statuses
thanks
I am expecting logic like this:
select timesheet_id,
(case when count(*) = 1 and min(status) = 'Posted' then min(status)
when count(*) = 1 then 'Error'
when min(status) = 'Adjusted' and max(status) = 'Posted' then 'Adjusted'
else NULL -- this case is not covered in the description
end) as new_status
from [TIME_DW].[dbo].[Timecard_Timesheets]
group by timesheet_id;
I don't understand what all the other columns are going in the code in the question.
This should get you going in the right direction:
First we count rows by TimeSheet Id (CN) and we assign a row_number (RN) ordered by "Adjusted" records first, then everything else (you might want to add an adjustment date as a 2nd order by to get the most recent one first).
Then we add an error status if the first and only row is not a Status of "Posted".
Finally we select out only the rows WHERE RN=1
DECLARE #TimeSheet TABLE (Id INT, Status VARCHAR(15))
INSERT INTO #TimeSheet (Id,Status)
VALUES
(1,'Posted'),
(2,'Posted'),
(2,'Adjusted'),
(3,'Adjusted')
;WITH X AS
(
SELECT COUNT(2) OVER(PARTITION BY Id) AS CN,
ROW_NUMBER() OVER(PARTITION BY Id ORDER BY CASE WHEN Status='Adjusted' THEN 0 ELSE 1 END) AS RN,
*
FROM #TimeSheet
), Y AS
(
SELECT CASE WHEN CN=1 AND RN=1 AND Status<>'Posted' THEN 'Error'
ELSE ''
END AS Error,
*
FROM X
)
SELECT *
FROM Y
WHERE RN=1
from your code, I think you were trying to do this :
SELECT
ts.[Resource NUID]
, ts.[Timesheet ID]
, ts.[Timesheet Start Date]
, ts.[Timesheet End Date]
, ts.[Timesheet Posted Date]
, ts.[Timesheet Status]
, ts.[RunSourceID]
, ts.[SpanStartDate]
, ts.[SpanEndDate]
FROM
[TIME_DW].[dbo].[Timecard_Timesheets] as ts
JOIN (
SELECT *
, CASE
WHEN TimeSheetCount > 1 AND [Timesheet Status] <> 'Posted' THEN 'Adjusted'
WHEN TimeSheetCount = 1 AND [Timesheet Status] <> 'Posted' THEN 'Error'
ELSE 'Posted'
END NewStatus
FROM (
SELECT *
, COUNT(*) OVER(PARTITION BY t1.[Timesheet ID]) TimeSheetCount
, ROW_NUMBER() OVER(ORDER BY t1.[Timesheet Start Date]) RN
FROM
[TIME_DW].[dbo].[Timecard_Timesheets] as t1
) D
) t2 ON ts.[Timesheet ID] = t2.[Timesheet ID]
WHERE
ts.[Resource NUID] = 'e066308'
AND ts.[Timesheet Status] <> 'Open'
AND ts.[Timesheet Status] <> 'Submitted'

Excluding 'Nulls' from alias column

hoping you guys can help me out. Am a trainee analyst so need a hand. Please see below query:
SELECT [PATHWAY_ID], [PAS_ID], [Patient_Name], [Pathway_Specialty], [Clinician],
[Referral_priority], [RTT_START_DTTM], [Days Waiting], [Activity Type],
[Last Activity Type], [Next_Appt_DTTM], [First_Appointment_Flag],
CASE WHEN [Days Waiting] <=97 AND [Next_Appt_DTTM] IS NOT NULL THEN 'Booked'
WHEN [Days Waiting] >=98 AND [Next_Appt_DTTM] IS NULL THEN 'Unbooked'
END AS 'Booked Status'
FROM [GWH_RTT].[rtt].[GWH_RTT_Nonadmitted_PTL]
WHERE [Referral_priority] = 'Routine'
ORDER BY 'Booked Status' DESC
In my alias column I have Nulls in there that don't match my case statement. How do I ask SQL to return my case statement excluding the Nulls in my alias column?
How about using a subquery or cte:
with q as (<your query here without the order by>)
select q.*
from q
where [Booked Status] is not null
order by [Booked Status];
A word of advice: don't use single quotes for column aliases. Only use single quotes for date and string constants. You can use square braces or double quotes in SQL Server.
Try this:
SELECT t.*
FROM (SELECT [PATHWAY_ID], [PAS_ID], [Patient_Name], [Pathway_Specialty], [Clinician],
[Referral_priority], [RTT_START_DTTM], [Days Waiting], [Activity Type],
[Last Activity Type], [Next_Appt_DTTM], [First_Appointment_Flag],
CASE WHEN [Days Waiting] <=97 AND [Next_Appt_DTTM] IS NOT NULL THEN 'Booked'
WHEN [Days Waiting] >=98 AND [Next_Appt_DTTM] IS NULL THEN 'Unbooked'
END AS 'Booked Status'
FROM [GWH_RTT].[rtt].[GWH_RTT_Nonadmitted_PTL]
WHERE [Referral_priority] = 'Routine'
) t
WHERE t.[Booked Status] IS NOT NULL
ORDER BY [Booked Status] DESC