Excluding 'Nulls' from alias column - sql

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

Related

Getting 2 result columns from SQL query

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

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

Subquery returned more than 1 rows inside case statement

I have been working on a query whereby in a subquery I am selecting the column Cust_Status under certain conditions.
select distinct
C.Cust_Code [Cust #],
C.Cust_Start_Date [Start Date],
C.Cust_End_date [End Date],
(select
Cust_Status = (case
when cast(CUST_UPDATE_DATE_LT as DATE) = cast('2017-01-23 00:00:00' as Date)
then 'V'
when cast(CUST_UPDATE_DATE_LT as DATE) = cast('2017-01-22 00:00:00' as Date)
then 'I'
end)
from tblCustomers) [Cust Status],
M.Machine_ID,
M.Machine_Location
from
tblCustomers C
inner join
tblMachine M on C.Cust_Mach_Pkey = M.Pkey
When I run this query I get an error
subquery returned more than 1 value error.
When I remove the subquery inside case, it's fine. But I am sure there is only 1 record present for both date conditions. So not sure how my subquery returning more than 1 values. Please enlighten me.
I am guessing that you just want to compare the latest date. If so, there are much simpler ways:
select C.Cust_Code as [Cust #], C.Cust_Start_Date as [Start Date],
C.Cust_End_date as [End Date],
(case when max(cast(CUST_UPDATE_DATE_LT as DATE)) = '2017-01-23'
then 'V'
when max(cast(CUST_UPDATE_DATE_LT as DATE)) = '2017-01-22'
then 'I'
end) as Cust_status
M.Machine_ID,
M.Machine_Location
from tblCustomers C inner join
tblMachine M
on C.Cust_Mach_Pkey = M.Pkey
group by C.Cust_Code, C.Cust_Start_Date, C.Cust_End_date,
M.Machine_ID, M.Machine_Location

Column invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause

We have a table which will capture the swipe record of each employee. I am trying to write a query to fetch the list of distinct employee record by the first swipe for today.
We are saving the swipe date info in datetime column. Here is my query its throwing exception.
select distinct
[employee number], [Employee First Name]
,[Employee Last Name]
,min([DateTime])
,[Card Number]
,[Reader Name]
,[Status]
,[Location]
from
[Interface].[dbo].[VwEmpSwipeDetail]
group by
[employee number]
where
[datetime] = CURDATE();
Getting error:
Column 'Interface.dbo.VwEmpSwipeDetail.Employee First Name' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Any help please?
Thanks in advance.
The error says it all:
...Employee First Name' is invalid in the select list because it is not contained
in either an aggregate function or the GROUP BY clause
Saying that, there are other columns that need attention too.
Either reduce the columns returned to only those needed or include the columns in your GROUP BY clause or add aggregate functions (MIN/MAX). Also, your WHERE clause should be placed before the GROUP BY.
Try:
select distinct [employee number]
,[Employee First Name]
,[Employee Last Name]
,min([DateTime])
,[Card Number]
,min([Reader Name])
from [Interface].[dbo].[VwEmpSwipeDetail]
where CAST([datetime] AS DATE)=CAST(GETDATE() AS DATE)
group by [employee number], [Employee First Name], [Employee Last Name], [Card Number]
I've removed status and location as this is likely to return non-distinct values. In order to return this data, you may need a subquery (or CTE) that first gets the unique IDs of the SwipeDetails table, and from this list you can join on to the other data, something like:
SELECT [employee number],[Employee First Name],[Employee Last Name].. -- other columns
FROM [YOUR_TABLE]
WHERE SwipeDetailID IN (SELECT MIN(SwipeDetailsId) as SwipeId
FROM SwipeDetailTable
WHERE CAST([datetime] AS DATE)=CAST(GETDATE() AS DATE)
GROUP BY [employee number])
Please Try Below Query :
select distinct [employee number],[Employee First Name]
,[Employee Last Name]
,min([DateTime])
,[Card Number]
,[Reader Name]
,[Status]
,[Location] from [Interface].[dbo].[VwEmpSwipeDetail] group by [employee number],[Employee First Name]
,[Employee Last Name]
,[Card Number]
,[Reader Name]
,[Status]
,[Location] having [datetime]=GetDate();
First find the first timestamp for each employee on the given day (CURDATE), then join back to the main table to get all the details:
WITH x AS (
SELECT [employee number], MIN([datetime] AS minDate
FROM [Interface].[dbo].[VwEmpSwipeDetail]
WHERE CAST([datetime] AS DATE) = CURDATE()
GROUP BY [employee number]
)
select [employee number]
,[Employee First Name]
,[Employee Last Name]
,[DateTime]
,[Card Number]
,[Reader Name]
,[Status]
,[Location]
from [Interface].[dbo].[VwEmpSwipeDetail] y
JOIN x ON (x.[employee number] = y.[employee number] AND x.[minDate] =Y.[datetime]
This should not be marked as mysql as this would not happen in mysql.
sql-server does not know which of the grouped [Employee First Name] values to return so you need to add an aggregate (even if you only actually expect one result). min/max will both work in that case. The same would apply to all the other rows where they are not in the GROUP BY or have an aggregate function (EG min) around them.

how to select columns with aggregate function sql server

i need to select two columns.1. calculate sum of one column and display it 2.display column as it is. so i tried below code
SELECT Sum(CONVERT(FLOAT, Replace(total, Char(0), ''))) AS Total,
[product name]
FROM tb_sales_entry_each_product
GROUP BY [sales date]
error message
Column 'tb_sales_entry_each_product.Product Name' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
where i made error.thanks
just need to group
select SUM(CONVERT(float, REPLACE(Total, CHAR(0), ''))) as Total, [Product Name]
from tb_sales_entry_each_product group by [Sales Date], [product name]
When ever you do a numercial count sum etc, any other columns need to be grouped.
thats all your missing
Try this:
select SUM(CONVERT(float, REPLACE(Total, CHAR(0), ''))) as Total,
[Product Name] ,[Sales Date]
from tb_sales_entry_each_product
group by [Sales Date],[Product Name]