Help with SQL CASE Statement in SELECT Query - sql

Here is my SQL statement:
SELECT [Item], SUM([Quantity]) AS SumOfQuantity, SUM([Price Each]) AS SumOfTotal,
([SumOfTotal] / [SumOfQuantity]) As Average,
CASE
WHEN [Average] <= 6 THEN SumOfTotal
ELSE 6*[SumOfQuantity] END AS GrossComm
FROM Data
GROUP BY [Item];
When I try to execute this query, I get the error message:
Syntax error (missing operator) in query expression 'CASE WHEN [Average] <= 6 THEN SumOfTotal ELSE 6*[SumOfQuantity] END AS GrossComm
Any ideas?
Thanks!

You can't reference a derived field by name in the CASE statement. Instead of [average] use the formulas.
You actually may have a larger issue since all your fields are based on other derived fields, so you might have to write out the formula for each one multiple times.
It's likely there is also an issue with your other fields that the CASE is obscuring. Basically don't refer to a calculated/aliased field in the same query by name, since it won't work.
If this is SQL Server you COULD do a workaround using a CTE:
;WITH CTE AS
(
SELECT [Item], SUM([Quantity]) AS SumOfQuantity, SUM([Price Each]) AS SumOfTotal,
FROM Data
GROUP BY [Item]
)
SELECT *, ([SumOfTotal] / [SumOfQuantity]) As Average,
CASE
WHEN ([SumOfTotal] / [SumOfQuantity]) <= 6 THEN SumOfTotal
ELSE 6*[SumOfQuantity] END AS GrossComm
FROM CTE

Related

Getting error Invalid column name days in sql server

I am working on sql query, When i run the query i am getting error Invalid column name 'days'., Can anyone please help me, why i am getting error like this, it looks like there something issue with having, but still not able to resolve it, here is my query
SELECT
COUNT(*) AS total
FROM
(
SELECT *, ABS(DATEDIFF(day, GETDATE(), EpStart)) AS [days]
FROM tb_Episode
HAVING [days] <= ''
) AS episodes
WHERE
(episodes.EOEClaimDate is NULL or episodes.EOEClaimDate = '0000-00-00') AND
episodes.PayerType = 'Ep' AND
episodes.EpEnd < '2018-02-05' AND
episodes.CustID = '27'
You can't use in HAVING clause the alias of your field.
Why you use HAVING instead of WHERE?
The same restriction for HAVING exists for WHERE,
So your query will become:
FROM
(
SELECT *, ABS(DATEDIFF(day, GETDATE(), EpStart)) AS [days]
FROM tb_Episode
WHERE ABS(DATEDIFF(day, GETDATE(), EpStart)) <= ''
) AS episodes
According to this answer by #Codo you cannot using a HAVING on an alias/virtual column as each SQL clause is performed in a designated order
FROM clause
WHERE clause
GROUP BY clause
HAVING clause
SELECT clause
ORDER BY clause
So because your column alias is defined after the HAVING clause you get the invalid column name error as the column doesn't technically exist yet.

SQL select from a Case when generated field

In my query there's this field is generated by this statement
CASE WHEN T1.unitMsr='MT' then STR((T1.Quantity),12,5)
ELSE STR((T1.Quantity*T2.NumInSale),12,5)END as OrderQty,
isnull(str(sum(CASE WHEN TN.unitMsr = 'MT'
Then TN.Quantity ELSE TN.Quantity*T2.NumInSale END),8,5),'0.00000') as DO_Qty_MT,
before the select statement ends, i would like to achieve something like this
Case When DO_Qty_MT >= OrderQty Then 'Normal'
Else 'Abnormal' END
As 'Closing method'
How should i substitute DO_Qty_MT and OrderQty with proper referencing?
The typical ways to add in such "variables" is to use a CTE or subquery. An alternative is a lateral join, which SQL Server supports with the apply keyword:
select . . ., v.OrderQty,
coalesce(str(sum(case when TN.unitMsr = 'MT'
then TN.Quantity
else TN.Quantity * T2.NumInSale
end), 8, 5
), '0.00000'
) as DO_Qty_MT,
from . . . outer apply
(values (case when T1.unitMsr = 'MT' then str(T1.Quantity, 12, 5)
else str(T1.Quantity * T2.NumInSale, 12, 5)
end)
) v(OrderQty)
This makes it simpler to do chains of calculations.
Also, I don't understand why you are using str(). Decimal/numeric would seem to do what you want -- and keep the representation of the value as a number not a string.
It seems to me that you are setting the order as "abnormal" if total order quantity is less than any of the order rows..
But this is possible only when T1.Quantity or T2.NumInSale are NULL or negative (when OrderQty<0).
Starting from you TN table you can simply test rows using:
-- get all rows with detailed information and Normal/Abnormal test..
select
*, Case When isnull(OrderQty, -1)<0 Then 'Abnormal' Else 'Normal' END As [Closing method]
from TN
Even simpler if you need only "Abnormal" rows
select *, 'Abnormal' As [Closing method]
from TN
where isnull(OrderQty, -1)<0
If you just want to extract Orders with abnormal rows use distinct YourOrderId instead of * in previous queries.
-- get all orders with Normal/Abnormal test
select distinct OrderId,
Case When isnull(OrderQty, -1)<0 Then 'Abnormal' Else 'Normal' END As [Closing method]
from TN
-- get only Abnormal orders
select distinct OrderId, 'Abnormal' As [Closing method]
from TN
where isnull(OrderQty, -1)<0

Query division returns 0

I am working on a query that devide 2 columns, I tried CAST and CONVERT but still returns 0. Will apperciate your help
SELECT a.Disposition,a.[Disposition Reason Breakdown],a.CSP,b.Total FROM
(
SELECT a.[Disposition],a.[Disposition Reason Breakdown],a.[CSP] FROM
(
SELECT [Disposition],[Disposition Reason Breakdown],COUNT(*) as CSP FROM [dbo].[Disposition]
WHERE [Disposition] <> 'Interested'
GROUP BY [Disposition],[Disposition Reason Breakdown]
) a
)a
INNER JOIN
(
SELECT a.Disposition,SUM(a.CSP) as Total FROM
(
SELECT [Disposition],[Disposition Reason Breakdown],COUNT(*) as CSP FROM [dbo].[Disposition]
WHERE [Disposition] <> 'Interested'
GROUP BY [Disposition],[Disposition Reason Breakdown]
)a
GROUP BY a.Disposition
)b ON a.Disposition = b.Disposition
I am using sql
I solved it, it turns out that I just used the wrong data type which in my case is decimal I should've thought of REAL here is the final query a.CSP/CAST(b.Total as REAL)

How to perform arithmetic on a column defined on a SELECT statement

SELECT DATEDIFF(MINUTE, j.start_time , j.end_time) as job_duration,
(jtype.cost_per_minute * job_duration) as job_cost
All the joins and from statements are done it runs without error when there is no arithmetic to be done but with the multiplication it gives an error. Not sure what to do. Any help would be appreciated thanks in advance.
Invalid column name 'job_duration'
job_duration does not exist until the query gets executed you can do it by nesting into another sql clause or by doing this:
SELECT DATEDIFF(MINUTE, j.start_time , j.end_time) AS job_duration, (jtype.cost_per_minute * DATEDIFF(MINUTE, j.start_time , j.end_time)) AS 'job_cost'
Another way to write that statement:
;with _CTE as
(
SELECT YourJobId, DATEDIFF(MINUTE, start_time , end_time) AS job_duration
from YourTableName
)
Select jtype.cost_per_minute * _CTE.job_duration AS 'job_cost'
from YourTableName as jType
inner join _CTE on jtype.YourJobId = _CTE.YourJobId

Accessing aliased fields in T-SQL

In a query I create lots of fields using the CASE expression.
I need to reference these fields later on in the query but it seems I can't access the field using its alias - I have to repeat the CASE expression every time I want to reference its value.
Is there a simple way to access these fields?
You can use CTEs (assuming SQL Server 2005+), like this very basic example:
DECLARE #Val INT
SET #Val = 1
;WITH CTEExample AS
(
SELECT CASE #Val WHEN 1 THEN 'A' ELSE 'B' END AS MyCaseField1
)
SELECT * FROM CTEExample WHERE MyCaseField1 = 'A'
why not simply make a subquery
eg
SELECT foo.column
FROM (
SELECT
CASE WHEN yourcase THEN 'a'
ELSE 'b'
END AS 'column'
FROM yourtable) AS foo
but this can be done with CTEs either (look at this answer)
You can also use CROSS APPLY for this as in this tip by Itzik Ben Gan.
SELECT SalesOrderID, OrderDate, Week_Day
FROM Sales.SalesOrderHeader
CROSS APPLY
(SELECT DATEPART(weekday, DATEADD(day, ##DATEFIRST - 7, OrderDate)) AS Week_Day) AS A
WHERE Week_Day NOT IN (1, 7);
You should be aware that reusing aliases in a where clause will render the predicate unsargable however so should be used with caution (this applies regardless of whether you use APPLY or a CTE)