The multi-part identifier "Transaction_tbl.locid" could not be bound while using join in case statement in sql server - sql

I have a query like this:
select sum(status_receved) as Receved, sum(status_parked) as Parked,
sum(status_requested) as Requested,sum(status_requestedinprocess) as Requestinprocess,
sum(status_deliverd) as Deliverd
from (select case when (status = 0 ) then 1 else 0 end as status_receved,
case when (status = 2) then 1 else 0 end as status_parked,
case when (status = 3) then 1 else 0 end as status_requested,
case when(status=4) then 1 else 0 end as status_requestedinprocess,
case when(Status=5) then 1 else 0 end status_deliverd
from transaction_tbl where locid in(5) and status in (0,2,3,4)) a
this query is working fine. i am getting result like this:
Receved Parked Requested Requestinprocess Deliverd
----------- ----------- ----------- ---------------- -----------
1 37 0 3 0
I also have a location_master table, and I want to show the corresponding location name before. My locid=5 is Bur dubai. I tried to write a query something like this:
SELECT LocName ,
SUM(status_receved) AS Receved ,
SUM(status_parked) AS Parked ,
SUM(status_requested) AS Requested ,
SUM(status_requestedinprocess) AS Requestinprocess ,
SUM(status_deliverd) AS Deliverd
FROM ( SELECT l.LocName ,
CASE WHEN ( status = 0 ) THEN 1
ELSE 0
END AS status_receved ,
CASE WHEN ( status = 2 ) THEN 1
ELSE 0
END AS status_parked ,
CASE WHEN ( status = 3 ) THEN 1
ELSE 0
END AS status_requested ,
CASE WHEN ( status = 4 ) THEN 1
ELSE 0
END AS status_requestedinprocess ,
CASE WHEN ( Status = 5 ) THEN 1
ELSE 0
END status_deliverd
FROM transaction_tbl t
INNER JOIN Location_tbl l ON l.Locid = t.locid
WHERE t.Locid IN ( 5 )
AND status IN ( 0, 2, 3, 4 )
) a;
But I am getting this error:Column 'a.LocName' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
The result I would like to get is this:
Location Receved Parked Requested Requestinprocess Deliverd
--- ----------- ----------- ----------- ---------------- -----------
Burdubai 1 37 0 3 0

It seems that SQL Server was installed with case-sensitive option. You can check: execute sp_server_info and look at 18 COLLATION_SEQ on sort_order.
On my server it is set to nocase_iso that means if you already have Column A column in a table you can not add a column: they are the same if sort_order is set to nocase_iso.
If so then just change on l.Locid=t.locid to proper case on l.Locid=t.Locid
Also in your query you are selecting l.LocName from subquery that doesn't return LocName column. Rewrite as
SELECT LocName ,
SUM(status_receved) AS Receved ,
SUM(status_parked) AS Parked ,
SUM(status_requested) AS Requested ,
SUM(status_requestedinprocess) AS Requestinprocess ,
SUM(status_deliverd) AS Deliverd
FROM ( SELECT l.LocName ,
CASE WHEN ( status = 0 ) THEN 1
ELSE 0
END AS status_receved ,
CASE WHEN ( status = 2 ) THEN 1
ELSE 0
END AS status_parked ,
CASE WHEN ( status = 3 ) THEN 1
ELSE 0
END AS status_requested ,
CASE WHEN ( status = 4 ) THEN 1
ELSE 0
END AS status_requestedinprocess ,
CASE WHEN ( Status = 5 ) THEN 1
ELSE 0
END status_deliverd
FROM transaction_tbl t
INNER JOIN Location_tbl l ON l.Locid = t.locid
WHERE t.Locid IN ( 5 )
AND status IN ( 0, 2, 3, 4 )
) a
GROUP BY LocName;

Related

Query to get a output in desired format

Proc type add sub multi div
1 A 1 0 1 1
1 B 2 2 0 1
Output should be in the format
Proc Aadd Asub Amulti Adiv Badd Bsub Bmulti Bdiv
1 1 0 1 1 2 2 0 1
A simple conditional aggregation should do the trick
Select Proc
,Aadd = max( case when type='A' then add else 0 end)
,Asub = max( case when type='A' then sub else 0 end)
,Amuti = max( case when type='A' then multi else 0 end)
,Adiv = max( case when type='A' then div else 0 end)
,Badd = max( case when type='B' then add else 0 end)
,Bsub = max( case when type='B' then sub else 0 end)
,Bmuti = max( case when type='B' then multi else 0 end)
,Bdiv = max( case when type='B' then div else 0 end)
From YourTable
Group By Proc
Another approach using CTE and Joins.
declare #table table(Proce int, type char(1), addi int, sub int, multi int, div int)
insert into #table values
(1,'A', 1, 0, 1, 1),
(1,'B', 2, 2, 0, 1);
;with cte_a as
(
SELECT proce, max(addi) as Aadd, max(sub) as Asub, max(multi) as Amulti, max(div) as Adiv
FROM #table where type = 'A'
group by proce
),cte_b as
(
SELECT proce, max(addi) as Badd, max(sub) as Bsub, max(multi) as Bmulti, max(div) as Bdiv
FROM #table where type = 'B'
group by proce
)
SELECT a.proce,a.aAdd, a.aSub, a.Amulti, a.Adiv,b.BAdd,b.bsub, b.bmulti, b.bdiv
from cte_a as a
join cte_b as b
on a.Proce = b.Proce
proce
aAdd
aSub
Amulti
Adiv
BAdd
bsub
bmulti
bdiv
1
1
0
1
1
2
2
0
1

SQL Query for repeat advertisers

I want to identify first time and repeat advertisers.
This is the code I had written,
but I am getting duplicate values and the advertiser's first order is flagged as a new customer and the subsequent ones as repeat.
SELECT DISTINCT (order_id )
, advertiser_id
, advertiser_name
, order_start_date
, source_type
, MIN(order_start_date) OVER (PARTITION BY advertiser_id) AS firstorderdate
, CASE WHEN (order_start_date) = (firstorderdate) THEN 1
ELSE 0
END AS isNewCustomer,
FROM advertising;
Current output
Advertiser isnewcustomer
A 0
A 1
B 0
C 0
D 1
D 1
Expected output
Advertiser isnewcustomer
A 1
B 0
C 0
D 1
You can try this.
select subqry.advertiser_id,
case when subqry.adv_count > 1 Then 1
ELSE 0
END as isNewCustomer FROM
( select advertiser_id, count(advertiser_id) as adv_count
from advertising
group by advertiser_id ) subqry;

SQL Server: Using COUNT with IN and NOT IN

I have a data table as follows :
file_id | action code
1 | 10
1 | 20
2 | 10
2 | 12
3 | 10
3 | 20
4 | 10
4 | 10
4 | 20
The output is:
file_id | Warning
1 | 0
2 | 0 <- this should be 1 instead
3 | 0
4 | 1
The first count works as expected, and sets warning as 1, if there are any action_code duplicates, but i can't get it to work and display a warning if action_code is not perfectly divisible with 10
#exported [int] = NULL,
#bin_id [int] = NULL,
#date_start [DateTime],
#date_stop [DateTime],
#action_code [int] = NULL,
#action_description [varchar](43) = NULL
SELECT
dbo.Tf.file_id AS 'ID',
dbo.Tf.file_name AS 'NAME',
MAX(dbo.TFD.action_date) AS 'DATE',
MAX(dbo.TFD.file_length) AS 'SIZE',
dbo.Bins.name AS 'BIN',
dbo.TFD.action_description,
CASE
WHEN (COUNT(DISTINCT dbo.TFD.action_code) <> COUNT(dbo.TFD.action_code) )
AND
((SELECT COUNT ( dbo.TFD.action_code ) FROM TFD WHERE action_code IN (10,20,30,40,50)) > 0
AND
(SELECT COUNT ( dbo.TFD.action_code ) FROM TFD WHERE action_code NOT IN (10,20,30,40,50)) > 0 ) THEN 1
ELSE 0
END AS 'Warning'
FROM
( SELECT
dbo.Tf.file_id,
MAX(dbo.TFD.action_code) AS 'action_code'
FROM Tf
INNER JOIN TFD
ON Tf.file_id = TFD.file_id INNER JOIN Bins ON Tf.bin_id = Bins.bin_id
WHERE
(#bin_id IS NULL OR Tf.bin_id = #bin_id)
AND Tf.file_id IN
(
SELECT H.file_id
FROM Tf AS H INNER JOIN TFD AS D ON H.file_id = D.file_id
WHERE ((D.action_date >= #date_start AND D.action_date <= #date_stop) OR (H.file_date >= #date_start AND H.file_date <= #date_stop))
AND (H.bin_id = #bin_id OR #bin_id IS NULL)
AND H.file_type = #exported
AND ((#action_description IS NULL) OR (D.action_description LIKE #action_description + '%'))
)
AND (#exported IS NULL OR Tf.file_type = #exported)
GROUP BY dbo.Tf.file_id) AS TempSelect
INNER JOIN Tf
ON Tf.file_id = TempSelect.file_id
INNER JOIN TFD
ON (TFD.file_id = TempSelect.file_id
AND TFD.action_code = TempSelect.action_code)
INNER JOIN Bins ON Tf.bin_id = Bins.bin_id
WHERE
(
(#action_code IS NULL ) OR (#action_code <> -1 AND TempSelect.action_code = #action_code)
OR (#action_code = -1 AND TempSelect.action_code NOT IN (10,20,30,40) )
)
GROUP BY
dbo.Tf.file_id,
dbo.Tf.file_name,
dbo.Bins.name,
dbo.Tf.bin_id,
dbo.TFD.action_description
EDIT: I added the whole procedure. My main goal,among others, is to set the field warning as 1 if the following conditions are met:
if there are any action_code duplicates (as it's the case for file 4)
if there is an action_code not divisible by 10 among the other action_codes for each file (as it's the case with file 2)
If your logic is: Set a flag to 1 if there are duplicates or if a code is not divisible by 10, then I would suggest:
select (case when count(distinct d.action_code) <> count(*) then 1
else max(case when d.action_code % 10 <> 0 then 1 else 0 end)
end)
Notice that I replaced dbo.Detail with the table alias d. Table aliases make a query easier to write, read, and understand.
Hope this helps you:
SELECT FILE_ID,
MAX(CASE WHEN action_code % 10 != 0 THEN 1 END) not_divisible,
CASE WHEN COUNT(*)!=COUNT(DISTINCT action_Code) THEN 1 END not_unique
FROM #test
GROUP BY FILE_ID
Putting it all together you can use:
SELECT file_id,
CASE WHEN COUNT(*)!=COUNT(DISTINCT action_Code) THEN 1
ELSE MAX(CASE WHEN action_code % 10 != 0 THEN 1 ELSE 0 END) END Warning
FROM #test
GROUP BY file_id
Try with the below query..
CREATE TABLE #t (FileID INT,ActionCode INT)
INSERT INTO #t
VALUES (1,10),(1,20),(2,10),(2,12),(3,10),(3,20),(4,10),(4,10),(4,20)
WITH cte_1
as (
SELECT *,COUNT(1) OVER(PARTITION BY FileID,ActionCode ORDER BY fileID,ActionCode) CNT
FROM #T)
SELECT FileID,case WHEN SUM(ActionCode) %10 <>0 THEN 1 WHEN MAX(CNT)<>1 THEN 1 ELSE 0 END
FROM CTE_1
GROUP BY FileID
Result :
Thanks all for your answers, they were helpful, i modified the following section as such, and now it works:
...
dbo.TFD.action_description,
CASE
WHEN (COUNT(DISTINCT dbo.TFD.action_code) <> COUNT(dbo.TFD.action_code)) OR err_ac > 0
THEN 1 ELSE 0 END AS 'Warning'
FROM
(
SELECT
dbo.Tf.file_id,
MAX(dbo.TFD.action_code) AS 'action_code',
CASE
WHEN SUM(dbo.TFD.action_code) %10 <> 0 THEN 1 ELSE 0 END AS 'err_ac'
...

Show only row with highest value

In my query I'm returning number of days a week something occurs. Everything is working fine, with the exception that I'm getting multiple rows returned where I only need the highest. So for example in my query, if the TotalDays is 3, I have a row for 1, 2 and 3. If its 4 then I have rows for 1,2,3 and 4, etc. What do I need to do so that I only get the highest one? I tried using both ROW_NUMBER and MAX but can't seem to figure out how to accomplish this with the CASES.
SELECT Employees.CustomerID, X.*, Customers.ReportID
FROM
(
SELECT
CASE WHEN [M] = '1' THEN 1 ELSE 0 END +
CASE WHEN [Tu] = '1' THEN 1 ELSE 0 END +
CASE WHEN [W] = '1' THEN 1 ELSE 0 END +
CASE WHEN [Th] = '1' THEN 1 ELSE 0 END +
CASE WHEN [F] = '1' THEN 1 ELSE 0 END +
CASE WHEN [Sa] = '1' THEN 1 ELSE 0 END +
CASE WHEN [Su] = '1' THEN 1 ELSE 0 END AS DaysofWeek
FROM
Customers
) X, Employees INNER JOIN ON Employees.EmployeesID = Customers.EmployeesID
GROUP BY Employees.CustomerID, Customers.ReportID, X.DaysofWeek
Few more details on this. For any given EmployeeID there can be unlimited ReportIDs and I want to return all of them but ONLY for where the DaysofWeek is the highest.
So EmployeeID 200 may have report 1001 and 1002 that are returned 2 days a week each. What should shows is
200 2 1001
200 2 1002
However, what is currently showing is:
200 1 1001
200 2 1001
200 1 1002
200 2 1002
Modified the query and added a couple more tables though everything is returning a value of 5.
WITH sub AS(
SELECT Shift1.EmployeeID, X.*, Schedule.Services, Schedule.ReportID
FROM
(
SELECT
CASE WHEN [M] = '1' THEN 1 ELSE 0 END +
CASE WHEN [Tu] = '1' THEN 1 ELSE 0 END +
CASE WHEN [W] = '1' THEN 1 ELSE 0 END +
CASE WHEN [Th] = '1' THEN 1 ELSE 0 END +
CASE WHEN [F] = '1' THEN 1 ELSE 0 END +
CASE WHEN [Sa] = '1' THEN 1 ELSE 0 END +
CASE WHEN [Su] = '1' THEN 1 ELSE 0 END AS DaysofWeek
FROM
Schedule
) X, Shift1 INNER JOIN (Shift2 INNER JOIN Schedule ON Shift2.Shift2ID = Schedule.Shift2ID) ON Shift1.Shift1ID = Shift2.Shift1ID
GROUP BY Shift1.EmployeeID, Schedule.Services, Schedule.ReportID, X.DaysofWeek
)
SELECT X.*
FROM sub X
JOIN (SELECT EmployeeID, ReportID, MAX(DaysofWeek) AS DaysofWeek
FROM sub
GROUP BY EmployeeID, ReportID) Y
ON X.DaysofWeek = Y.DaysofWeek
and X.EmployeeID = Y.EmployeeID
and X.ReportID = Y.ReportID
First, your query should look like:
SELECT e.CustomerID, c.DaysOfWeek, c.ReportId
FROM (SELECT c.*,
(CASE WHEN [M] = '1' THEN 1 ELSE 0 END +
CASE WHEN [Tu] = '1' THEN 1 ELSE 0 END +
CASE WHEN [W] = '1' THEN 1 ELSE 0 END +
CASE WHEN [Th] = '1' THEN 1 ELSE 0 END +
CASE WHEN [F] = '1' THEN 1 ELSE 0 END +
CASE WHEN [Sa] = '1' THEN 1 ELSE 0 END +
CASE WHEN [Su] = '1' THEN 1 ELSE 0 END
) AS DaysofWeek
FROM Customers c
) c JOIN
Employees e
ON e.EmployeesID = c.EmployeesID
GROUP BY e.CustomerID, c.ReportID, c.DaysofWeek;
I question the join (why would Employee.CustomerId not join to the Customers table?), but this is how you have it. To get the reports with the biggest day of the week, use DENSE_RANK():
SELECT e.CustomerID, c.DaysOfWeek, c.ReportId
FROM (SELECT c.*, DENSE_RANK() OVER (PARTITION BY c.EmployeesId ORDER BY DaysOfWeek DESC) as seqnum
FROM (SELECT c.*,
(CASE WHEN [M] = '1' THEN 1 ELSE 0 END +
CASE WHEN [Tu] = '1' THEN 1 ELSE 0 END +
CASE WHEN [W] = '1' THEN 1 ELSE 0 END +
CASE WHEN [Th] = '1' THEN 1 ELSE 0 END +
CASE WHEN [F] = '1' THEN 1 ELSE 0 END +
CASE WHEN [Sa] = '1' THEN 1 ELSE 0 END +
CASE WHEN [Su] = '1' THEN 1 ELSE 0 END
) AS DaysofWeek
FROM Customers c
) c
) c JOIN
Employees e
ON e.EmployeesID = c.EmployeesID
WHERE seqnum = 1
GROUP BY e.CustomerID, c.ReportID, c.DaysofWeek;
The query itself might be able to get cleaned a little better, however if your current query is working and showing you the output you've indicated, but you want to reduce it to what you indicate is your desired output, you should be able to use the with clause to do this as follows:
with sub as(
SELECT Employees.CustomerID, X.*, Customers.ReportID
FROM
(
SELECT
CASE WHEN [M] = '1' THEN 1 ELSE 0 END +
CASE WHEN [Tu] = '1' THEN 1 ELSE 0 END +
CASE WHEN [W] = '1' THEN 1 ELSE 0 END +
CASE WHEN [Th] = '1' THEN 1 ELSE 0 END +
CASE WHEN [F] = '1' THEN 1 ELSE 0 END +
CASE WHEN [Sa] = '1' THEN 1 ELSE 0 END +
CASE WHEN [Su] = '1' THEN 1 ELSE 0 END AS DaysofWeek
FROM
Customers
) X INNER JOIN Employees ON Employees.EmployeesID = Customers.EmployeesID
GROUP BY Employees.CustomerID, Customers.ReportID, X.DaysofWeek
)
select x.*
from sub x
join (select customerid, reportid, max(daysofweek) as daysofweek
from sub
group by customerid, reportid) y
on x.daysofweek = y.daysofweek
and x.customerid = y.customerid
and x.reportid = y.reportid
Also your join clause was off.

SQL query rewrite for prettification and or performance improvement

I have a query that essentially amounts to:
Select query 1
Union
Select query 2
where rowid not in query 1 rowids
Is there a prettier / more performant way to do this? I'm assuming the results of query 1 would be cached and thus utilized in the union... but it's also kinda oogly.
Update with the original query:
SELECT FruitType
, count(CASE WHEN Status = 0 THEN 1 ELSE 0 END) AS Fresh
, count(CASE WHEN Status = 1 THEN 1 ELSE 0 END) AS Ripe
, count(CASE WHEN Status = 2 THEN 1 ELSE 0 END) AS Moldy
FROM FruitTypes FT1
LEfT JOIN Fruits F on F.FTID = FT1.ID
where
Fruit.IsHighPriced = 0
GROUP BY FruitType
Union ALL
select FruitType, 0 as Fresh, 0 as Ripe, 0 as Moldy
FROM FruitTypes ft3
where
ft3.StoreID = #PassedInStoreID
and FruitType NOT IN
(
SELECT FruitType
, count(CASE WHEN Status = 0 THEN 1 ELSE 0 END) AS Fresh
, count(CASE WHEN Status = 1 THEN 1 ELSE 0 END) AS Ripe
, count(CASE WHEN Status = 2 THEN 1 ELSE 0 END) AS Moldy
FROM FruitTypes FT2
LEfT JOIN Fruits F on F.FTID = FT2.ID
where
Fruit.IsHighPriced = 0
GROUP BY FruitType
)
Thanks!
You don't need the second case statement in the NOT in clause. And not Exists is often faster in SQL Server.
SELECT FruitType
, count(CASE WHEN Status = 0 THEN 1 ELSE 0 END) AS Fresh
, count(CASE WHEN Status = 1 THEN 1 ELSE 0 END) AS Ripe
, count(CASE WHEN Status = 2 THEN 1 ELSE 0 END) AS Moldy
FROM FruitTypes FT1
LEfT JOIN Fruits F on F.FTID = FT1.ID
where
Fruit.IsHighPriced = 0
GROUP BY FruitType
Union ALL
select FruitType, 0 as Fresh, 0 as Ripe, 0 as Moldy
FROM FruitTypes ft3
where
ft3.StoreID = #PassedInStoreID
and NOT EXISTS
(
SELECT *
FROM FruitTypes FT2
LEfT JOIN Fruits F on F.FTID = FT2.ID
where
Fruit.IsHighPriced = 0
and ft3.FruitType = FT2.FruitType
)
The prettiest way of writing would probably be by turning query #1 into a view or a function, then using that view or function to call the repetitious code.
Performance could possibly be improved by using query #1 to fill a temp table or table variable, then using that temp table in place of the repititious code.