Invalid Column Name in case statement - sql-server

Im getting Invalid Column Name 'Average'. When Im writing without alias name it work. But I have too much condition.
SELECT
ST_LAWERP_PERFORMANCE_EVALUATION_ENTRIES.EMPLOYEEID,
Employees.EMPLOYEENAMESURNAMEFORMAT AS LastFirstName,
(CAST(SUM(EVALUATION) AS FLOAT)
/
(SELECT TOP 1
COUNT(*)
FROM ST_LAWERP_PERFORMANCE_EVALUATION_ENTRIES
WHERE DATE BETWEEN '2013-01-01' AND '2013-12-12' AND TYPE=2 AND SUPERVISORID=1020 GROUP BY EmployeeID )) AS AVERAGE,
CASE WHEN AVERAGE=1
THEN 'GOOD' END AS EVALUATION
FROM ST_LAWERP_PERFORMANCE_EVALUATION_ENTRIES INNER JOIN Employees
ON ST_LAWERP_PERFORMANCE_EVALUATION_ENTRIES.EMPLOYEEID=Employees.EmployeeID
WHERE DATE BETWEEN '2013-01-01' AND '2013-12-12' AND TYPE=2 AND ST_LAWERP_PERFORMANCE_EVALUATION_ENTRIES.SUPERVISORID=1020 AND ACTIVESTATUS=1
GROUP BY
ST_LAWERP_PERFORMANCE_EVALUATION_ENTRIES.EMPLOYEEID,
EMPLOYEENAMESURNAMEFORMAT

Try THis
SELECT *,case when average =1 then 'good' end as evaluation from(
select
ST_LAWERP_PERFORMANCE_EVALUATION_ENTRIES.EMPLOYEEID,
Employees.EMPLOYEENAMESURNAMEFORMAT AS LastFirstName,
(CAST(SUM(EVALUATION) AS FLOAT)
/
(SELECT TOP 1
COUNT(*)
FROM ST_LAWERP_PERFORMANCE_EVALUATION_ENTRIES
WHERE DATE BETWEEN '2013-01-01' AND '2013-12-12' AND TYPE=2 AND SUPERVISORID=1020 GROUP BY EmployeeID )) AS AVERAGE
FROM ST_LAWERP_PERFORMANCE_EVALUATION_ENTRIES INNER JOIN Employees
ON ST_LAWERP_PERFORMANCE_EVALUATION_ENTRIES.EMPLOYEEID=Employees.EmployeeID
WHERE DATE BETWEEN '2013-01-01' AND '2013-12-12' AND TYPE=2 AND ST_LAWERP_PERFORMANCE_EVALUATION_ENTRIES.SUPERVISORID=1020 AND ACTIVESTATUS=1
GROUP BY
ST_LAWERP_PERFORMANCE_EVALUATION_ENTRIES.EMPLOYEEID,
EMPLOYEENAMESURNAMEFORMAT) as subquery

Related

SQL - Return a value sum only once when grouped

I want to count the unique record of a string but grouping by dates, and if the string already appeared previously on a group it shouldn't be counted anymore.
I've tried using distinct and it does show the unique count of the record but the record is counted again on every month.
Actual and minified SQL query:
select
date,
count(distinct d.name) as count
from ...
group by date
Sample and desired output
Image
Grab unique names and tag them with the earliest date. At that point it's just a matter of regrouping the resulting rows by date. Each name will uniquely correspond to only one date as desired:
with data as (select name, min("date") as dt from T group by name)
select dt, count(name) as cnt from data group by dt;
If you still need to see the original dates even when no names are counted, then flag each row according to whether it should be counted and then count the flags per date:
with data as (
select *,
case when "date" = min("date") over (partition by name)
then 1 end as flag
from T
)
select "date", count(flag) as cnt
from data
group by "date";
So you want the name only count once:
SELECT COUNT(u.name) as name_count, u.[date]
FROM (
SELECT d.name,MIN(d.date) AS [date]
FROM yourTable d
GROUP BY d.name) u
GROUP BY u.[date];
You can add a ROW_NUMBER() that is Partitioned by name and ordered by date and add a WHERE clause that only returns the rows with Row_Number = 1.
You can check this following option-
SELECT A.Date,COUNT(B.[Name]) Count
FROM
(
SELECT DISTINCT Date FROM your_table
)A
LEFT JOIN
(
SELECT * FROM
(
SELECT *,ROW_NUMBER() OVER(PARTITION BY [Name] ORDER BY Date) RN
FROM your_table
)A WHERE RN = 1
)B ON A.Date = B.Date
GROUP BY A.Date
But the best option if I modify a bit the concept from Shawnt00 is as below-
SELECT A.Date,COUNT(B.[Name]) Count
FROM
(
SELECT DISTINCT Date FROM your_table
)A
LEFT JOIN
(
SELECT [Name],MIN(Date) Date FROM your_table GROUP BY [Name]
)B ON A.Date = B.Date
GROUP BY A.Date
Both case the output will be-
Date Count
20190101 2
20190201 0
20190301 1

Subquery distinct field

Hello I am learning to write sql queries and I am trying to query a ledger table to SELECT a field "ENCID" where there are more than 4 distinct values in a separate file "TDATE" for each distinct ENCID.
Then filter by a 3rd field "ITEMTYPE"
This is what I have:
SELECT
[ENCID]
,[PATIENTID]
,[ITEMTYPE]
,[Service Date]
,[Transaction Date]
,[Trans]
,[PracticeName]
FROM TABLE1
WHERE ITEMTYPE = 'S'
AND ENCID IN (SELECT ENCID FROM TABLE1 WHERE Count(Distinct [Transaction Date]) >4
AND ITEMTYPE = 'S')
I am getting this error "DataSource.Error: Microsoft SQL: An aggregate may not appear in the WHERE clause unless it is in a subquery contained in a HAVING clause or a select list, and the column being aggregated is an outer reference."
Try this instead:
SELECT
[ENCID]
,[PATIENTID]
,[ITEMTYPE]
,[Service Date]
,[Transaction Date]
,[Trans]
,[PracticeName]
FROM TABLE1
WHERE ITEMTYPE = 'S'
AND ENCID IN (
SELECT ENCID
FROM TABLE1
WHERE ITEMTYPE = 'S'
GROUP BY ENCID
HAVING Count(Distinct [Transaction Date]) >4
AND MAX ([Transaction Date]) - MIN ([Transaction Date]) > 60
)
Generally, aggregate functions can only be used in SELECT, HAVING, and ORDER BY clauses (as WHERE determines exactly which records are being aggregated).
What the error message is surprisingly elaborating on is the unique cases where WHERE may contain an aggregate function. Such as this:
SELECT a.id
FROM a
GROUP BY a.id
HAVING a.id IN (
SELECT b.a_id
FROM b
WHERE b.total = COUNT(a.something)
)

Using BETWEEN operator in CASE (THEN) statement

I am trying the following but its throwing an error, can someone tell me what I am doing wrong?
SELECT custType, count(*)
FROM tbl1 a
LEFT JOIN tbl2 b ON a.tbID = b.tbID
AND ((CustType IN ('Apple','IPAD') and date BETWEEN #StartDate AND #EndDate)
or (CustType IN ('Samsung','LCD') and date BETWEEN #StartDateLL AND #EndDateLL))
GROUP BY CustType
Why don't use AND/OR
SELECT CustType , count(*)
FROM tbl1 a
LEFT JOIN tbl2 b ON a.tbID = b.tbID
AND ((CustType IN ('Apple','IPAD') and date BETWEEN #StartDate AND #EndDate)
or (CustType IN ('Samsung','LCD') and date BETWEEN #StartDateLL AND #EndDateLL))
group by CustType ;
EDIT You can't group by CustType and Select *
You cannot use a BETWEEN operator for the THEN part of a case statement or IIF. BETWEEN is the condition that translates to true and false. So it is VALUE BETWEEN A AND B and would be apart of the WHEN section of a case statement.
Also the case statement returns a value not a formula to be further executed.
I agree with #Vercelli's solution but to show you how a case statement works in the method you are trying you could do the following:
SELECT *
FROM tbl1 a
LEFT JOIN tbl2 b ON a.tbID = b.tbID
AND (CASE
WHEN CustType IN ('Apple','IPAD') AND [date] ETWEEN #StartDate AND #EndDate THEN 1
WHEN CustType IN ('Samsung','LCD') AND [date] BETWEEN #StartDateLL AND #EndDateLL THEN 1
ELSE 0 END) = 1
Again go with #vercelli's answer as it is the more appropriate way of writing the SQL query.

Select and count statement

I am new and learning SQL on Microsoft SQL Server 2008. I am trying to do the following for a table of order line items each record is one order item.
any transaction numbers with only one record and a code of #####.
I have tried many ways but haven't been able to figure it out
Select * from Table
where count(transactionnumber)<2 and Code='9987'
I think I got it. Had to use a different code because QA didn't have an distinct rows with that code. Let me know if you see anything that might cause and issue.
Select * from (select Orders.TransactionNumber from Orders
group by Orders.TransactionNumber
having COUNT (Orders.TransactionNumber)=1) as transa
Inner join Orders on transa.TransactionNumber=Orders.TransactionNumber
where ItemCode=9803
Ended up with this code
use XXX
Select Orders.TransactionNumber,Orders.RepNumber, Orders.CustomerID,Orders.ShipToId,orders.ItemCode,Orders.Quantity,Orders.ReceivedDate,Orders.TransmitStatus from (select TransactionNumber from Orders
group by TransactionNumber
having COUNT (TransactionNumber)=1) as transa
Inner join Orders on Orders.TransactionNumber=transa.TransactionNumber
where ItemCode=9987 and ReceivedDate > DateADD (day, -1, GetDate() )
IF ##ROWCOUNT > 0
BEGIN
EXEC msdb.dbo.sp_send_dbmail
recipients=N'XXXX',
#body='Merchandisers orders with only Item Code 9803',
#subject ='only Item Code 9803',
#profile_name ='',
#query = 'Select Orders.TransactionNumber,Orders.RepNumber,Orders.CustomerID,Orders.ShipToId,orders.ItemCode,Orders.Quantity,Orders.ReceivedDate,Orders.TransmitStatus from(select TransactionNumber from Orders
group by TransactionNumber
having COUNT (TransactionNumber)<2) as transa
Inner join Orders on Orders.TransactionNumber=transa.TransactionNumber
where ItemCode=9803 and ReceivedDate > DateADD (day, -1, GetDate() )'
END'
Your query should include something to group by (Name, TransactionNumber, etc.) do a count and constrain on that.
SELECT TransactionCode, COUNT(*)
FROM TABLE
GROUP BY TransactionCode
HAVING COUNT(*) < 2
AND ItemCode = 9987
You may consider using the OVER keyword, so that you don't need to muck around the count(*) and group by so much. That way you can see counts without grouping.
Select *, count(*) over (partition by transactioncode) as "TheCounts"
from table
--where itemcode = 9903
or
Select *, count(*) over (partition by transactioncode, itemcode) as "TheCounts"
from table
--where itemcode = 9903
Here is what I ended up with on this that seems to be working correctly for about a week now it executes a sp_send_dbmail only if there are records.
Select Orders.TransactionNumber, Orders.RepNumber, Orders.CustomerID,Orders.ShipToId,orders.ItemCode,Orders.Quantity,Orders.ReceivedDate,Orders.TransmitStatus from (select TransactionNumber from Orders
group by TransactionNumber
having COUNT (TransactionNumber)=1) as transa
Inner join Device_Orders on Orders.TransactionNumber=transa.TransactionNumber
where ItemCode=9987 and ReceivedDate > DateADD (day, -1, GetDate() )
IF ##ROWCOUNT > 0

Equivalent to doing a join after the group by

I am looking to merge the following two queries into one:
select top 100 date, count(*) from sections
where content not like '%some condition%'
group by date
order by date;
select top 100 date, count(*) from sections
group by date
order by date;
It is like this question, LEFT JOIN after GROUP BY? except that I need this to work for MS SQL Server, not MySQL (the difference being that MSSQL does not allow subqueries in the from clause).
I am looking for a way to have the result set have three columns, date, the first count(*), and the second count(*).
My current solution is:
select top 100 date,
(select count(*) from sections s1
where content not like '%some condition%'
and s1.date = s2.date),
(select count(*) from sections s1
where s1.date=s2.date) from sections as s2
group by date
order by date;
Is there a better way to do this?
Try this:
with q1 as (select top 100 date, count(*) total from sections
where content not like '%some condition%'
group by date),
q2 as (select top 100 date, count(*) total from sections
group by date)
select q1.date, q1.total total1, q2.total total2
from q1
join q2 on q1.date = q2.date
order by q1.date
UPDATE:
Or this:
select date,
count(*) total,
sum(has_condition) total_condition
from (select top 100
date,
case when content not like '%some condition%' then 1
else 0 end has_condition
from sections ) t
group by date
order by date;
I did not do any triout, but that is the idea.
This is the query that do the job with just one select:
select top 100 date,
count(*) as count_all,
sum (
case
when content not like '%some condition%' then 1
else 0
end
) as count_condition
from sections
group by date
order by date
I am also pasting a working snippet from AdventureWorks2012 database
select top 100
ModifiedDate,
count(*) as count_all,
sum (
case when CarrierTrackingNumber not like '4911%' then 1
else 0
end
) as count_condition
from [Sales].[SalesOrderDetail]
group by ModifiedDate
order by ModifiedDate
For you reference you can use subqueries after FROM clause in SQL Server.

Resources