use recently defined alias in sql in case when - sql

I'm trying to clean up a product column in a sql table when querying. My (fake example) query looks like the following:
select
Id
, Name
, ProductName
, CASE
WHEN ProductName IN ('macbook', 'dell', 'air', 'hp') THEN 'Laptop'
WHEN ProductName IN ('ipod', 'walkman', 'headset') THEN 'Music_Device'
WHEN ProductName IN ('mop', 'broom', 'sponge') THEN 'Household Utilities'
WHEN ProductName IN ('bike', 'bike_2', 'bike_3') THEN 'Bicycle'
WHEN ProductName IN ('tesla', 'ford', 'prius') THEN 'Car'
ELSE null
END AS Prod_Group
, CASE
WHEN Prod_Group IN ('Laptop', 'Music_Device') THEN 'Electronics'
WHEN Prod_Group IN ('Bicycle', 'Car') THEN 'Transportation'
WHEN Prod_Group IN ('Household Utilities') THEN 'Utilities'
ELSE null
END AS Line_of_Business
from prod_database
Is there no way to reference an aliased column? Would I have to repeat my whole case when statement and change Laptop to Electronics etc.? I'm coming from R and learning SQL, so this is a bit new to me.

In Sql Server, we can use Cross Apply
SELECT Id,
NAME,
ProductName,
cs.Prod_Group,
CASE
WHEN cs.Prod_Group IN ( 'Laptop', 'Music_Device' ) THEN 'Electronics'
WHEN cs.Prod_Group IN ( 'Bicycle', 'Car' ) THEN 'Transportation'
WHEN cs.Prod_Group IN ( 'Household Utilities' ) THEN 'Utilities'
ELSE NULL
END AS Line_of_Business
FROM prod_database
CROSS apply (SELECT CASE
WHEN ProductName IN ( 'macbook', 'dell', 'air', 'hp' ) THEN 'Laptop'
WHEN ProductName IN ( 'ipod', 'walkman', 'headset' ) THEN 'Music_Device'
WHEN ProductName IN ( 'mop', 'broom', 'sponge' ) THEN 'Household Utilities'
WHEN ProductName IN ( 'bike', 'bike_2', 'bike_3' ) THEN 'Bicycle'
WHEN ProductName IN ( 'tesla', 'ford', 'prius' ) THEN 'Car'
ELSE NULL
END) cs (Prod_Group)

You could refer to with a CTE I suppose...
WITH CTE
AS
(
SELECT CASE WHEN 1>0 THEN 'A' END AS derivedCol
)
SELECT CASE WHEN derivedCol < 'B' THEN 'Pos1' ELSE 'Other' END
FROM CTE

--could use a real table here
declare #prodTypes as table
(ProductName varchar(50),
ProductGroup varchar(50),
Line_of_Business varchar(50));
insert into #prodTypes
values ('macbook', 'Laptop', 'Electronics'),
('dell', 'Laptop', 'Electronics'),
('hp', 'Laptop', 'Electronics'),
('ipod', 'Music_Device', 'Electronics')
-- etc.
-- the results you want:
select
p.Id
, p.Name
, p.ProductName
, pt.ProductGroup
, pt.Line_of_Business
from prod_database p
left join #prodTypes pt
on p.ProductName = pt.ProductName
-- to double check your settings you can do:
select Line_of_business, ProductGroup, ProductName
from #prodTypes
order by Line_of_business, ProductGroup, ProductName

Related

Insert occasionally missing rows

I am running below query, sometimes these query skip few records to insert into newordersholdentry and didn't get any error.
but if run same query again after finding it is missed some records for order, it will insert all.
Please let me know what could be the reason.
INSERT INTO newordersholdentry
(itemid,
lookupcode,
description,
gamacode,
ordered,
IsForceItem,
Scanned,
Location,
SortOrder
)
SELECT ID,
ItemLookupCode,
Description,
GamaCode,
SUM(Qty) AS Qty,
ForceItem,
0 AS Scanned,
SubDescription1,
Sortorder
FROM
(
SELECT Item.ID,
Item.ItemLookupCode,
Item.Description,
NewOrderItems.GamaCode,
NewOrderItems.Qty,
Item.SubDescription1,
Item.Binlocation,
ISNULL(
(
SELECT TOP (1) SortSno
FROM NewOrderPickPackSorting
WHERE(Bin = LEFT(Item.SubDescription1, 3))
), 99999) AS Expr1,
0 AS ForceItem,
p.sortorder
FROM NewOrderItems(NOLOCK)
INNER JOIN Item(NOLOCK) ON NewOrderItems.GamaCode = Item.SubDescription2
LEFT OUTER JOIN pickpath(NOLOCK) p ON concat(RTRIM(p.aisle), '-', p.section) = UPPER(LEFT(item.subdescription1, 6))
WHERE(NewOrderItems.Discontinue = 0)
AND (NewOrderItems.OrderID = 123456)
) AS t
Group by ID
, ItemLookupcode
, Description
, GAMACODE
, ForceItem
, Expr1
, BinLocation
, SubDescription1
, sortorder

Group accounts by 1 condition vs 2 conditions

I am trying to get a count of pat_id that were either only "Sent" or only "Sent and Received"
Here is my query so far
select pat_id,
(case when addr_msg_actn_c in(1) then 'Sent' else convert(varchar(10),'Received') end) [Status]
from pat_addr_verif
where pat_id in ('Z1000354','Z1000363','Z1000392','Z1000394')
group by pat_id, addr_msg_actn_c
order by pat_id
Which generates this output
However, I'd like to simplify the output to display like this
Here's a small proof of concept. You can generate a case statement on the sum of a value to choose which text string you want.
CREATE TABLE #SentReceive (
Pat_ID NVARCHAR(8)
,[status] TINYINT
)
INSERT INTO #SentReceive
VALUES ( 'Z1000354' ,1 )
,( 'Z1000354' ,1 )
,( 'Z1000363' ,1 )
,( 'Z1000363' ,2 )
,( 'Z1000392' ,2 )
,( 'Z1000394' ,1 )
,( 'Z1000394' ,2 )
SELECT pat_id
,sentstatus = CASE sum(distinct [status])
WHEN 1
THEN 'Sent'
WHEN 2
THEN 'Received'
WHEN 3
THEN 'Sent and Received'
END
FROM #SentReceive
GROUP BY pat_id
ORDER BY pat_id
create table SentReceive
(
Pat_ID nvarchar(8),
SentOnly nvarchar(8)
)
insert SentReceive
values
('Z1000354','Sent'),
('Z1000363','Sent'),
('Z1000363','Received'),
('Z1000392','Sent'),
('Z1000394','Sent'),
('Z1000394','Received')
select distinct a.Pat_ID,
case
when b.SentOnly is not null then
case a.SentOnly
when 'Received' then b.SentOnly + ' and ' + a.SentOnly
else a.SentOnly + ' and ' + b.SentOnly
end
else a.SentOnly
end as Status
from SentReceive a
left join SentReceive b on a.Pat_ID = b.Pat_ID and a.SentOnly <> b.SentOnly
I did a quickie with only the available data that you provided. If there are other variations in your dataset then you will need to account for that and it may or may not change what I came up with. Good luck!
Here is what I came up with:
;with cte as
(
select 1 as _order, 'Z1000354' as pat_id, 'Sent' as SentOnly
union select 2, 'Z1000363', 'Sent'
union select 3, 'Z1000363', 'Received'
union select 4, 'Z1000392', 'Sent'
union select 5, 'Z1000393', 'Received'
union select 5, 'Z1000394', 'Sent'
union select 6, 'Z1000394', 'Received'
)
select pat_id, replace(_Status,',',' and') as _Status
from(
select distinct pat_id,
STUFF((Select ', '+SentOnly
from cte T2
where T1.pat_id=T2.pat_id
FOR XML PATH('')),1,1,'') as _Status from cte T1
) a
where _Status in (' Sent', ' Sent, Received')
Final query with some help from above posters:
select distinct a.pat_id,
case when b.ADDR_MSG_ACTN_C is not null
then 'Sent and Received' else 'Sent Only' end as Status
from pat_addr_verif a
left join pat_addr_verif b on a.pat_id = b.pat_id and
a.ADDR_MSG_ACTN_C <> b.ADDR_MSG_ACTN_C
where a.pat_id in ('Z1000354','Z1000363','Z1000392','Z1000394')
Correct Final Output

always get a "not a GROUP BY expression" exception

The select part is fine, I can run it and get result, but if I insert the query result into a table, the "not a group by expression" exception was thrown, see my sql statement below:
INSERT INTO RAWDATA_FACT
(
LINEITEMID
,CALENDARYEAR
,CALENDARQUARTER
,CALENDARMONTH
,DEPARTMENTID
,PRODUCTID
,DEALERID
,ACTUALVALUE
,TARGETVALUE
,AGGREGATION
,TODATE
,CREATEDATE
,BATCH_ID
)
select parentid
,calendaryear
,calendarquarter
,calendarmonth
,departmentid
,productid
,dealerid
,sum(case when unaryoperator = '-' then actualvalue * (-1)
when unaryoperator = '~' then actualvalue * 0
else actualvalue
end
) actualvalue
,sum(case when unaryoperator = '-' then targetvalue * (-1)
when unaryoperator = '~' then targetvalue * 0
else targetvalue
end
) targetvalue
,aggregation
,todate
,sysdate createdate
,'201808' batch_id--v_batch_ID
from
(
select
x.parentid
, x.unaryoperator
, y.calendaryear
, y.calendarquarter
, y.calendarmonth
, y.departmentid
, y.productid
, y.dealerid
, y.actualvalue
, y.targetvalue
, y.aggregation
, y.todate
from
(select substr(lineitemid,instr(lineitemid,'_')+1) lineitemid,
parentid, unaryoperator from lineitem_temp where levelid = 14 /*v_cur_level*/) x
inner join
(select lineitemid,calendaryear, calendarquarter, calendarmonth, departmentid, productid, dealerid,
coalesce(actualvalue,0) actualvalue,coalesce(targetvalue,0) targetvalue,
aggregation, todate
from RAWDATA_FACT where BATCH_ID = '201808'/*v_batch_ID*/) y --eg. 201809
on x.lineitemid = y.lineitemid
--parent node's id contains "_" will not take part in calculation from current level to parent level
where regexp_like(x.parentid , '^\d+$') and not exists
--parent node contains formula will not participate calculation from current level to parent level
(select 1 from LINEITEM_TEMP where lineitemid = x.parentid and custommember is not null)
) t
GROUP BY
t.parentid
, t.calendaryear
, t.calendarquarter
, t.calendarmonth
, t.departmentid
, t.productid
, t.dealerid
, t.aggregation
, t.todate
;
who can tell me why? is there a way to insert the result into that table? If I run the select parts, it works fine, but if I want to insert the result into that table, it reports that exception.

SQL Server query result for all shipping products

I have a product table as below.
Where I want to get each product detail where its product_ship_flag is "YES" for all the products of same the order_number. If any of the product_ship_flag is "No" then the whole order_number should not be in the output. If all product_ship_flag as "No" then should not be in the output.
The Output will look like:
Thanks in advance.
Edited: Few members are not even trying to understand the problem, And some are not able to answer the problem so devoting the question. Please show some sportiness.
Try this.
If the inner query does not return anything for that order that means all the product has flag_ship equal to Yes
select * from product p
where not exists (
select '1' from product p2
where p2.order_number = p1.order_number
and p2.product_ship_flag = 'No')
Isn't that a basic query like this works?
Select * from product where product_ship_flag = 'Yes' group by order_number
Try with this query:
select * from product where orderno not in (select orderno, count(case when product_ship_flaf='No' then 1 end) from product
group by orderno
having count(case when product_ship_flaf='No' then 1 end)>=1)A
#irfan_m, the logic can be captured with the MIN operator. When you do a subquery and using a column called flag for example. You can easily pull out the orders based on your requirement.
See a mock up below:
DECLARE #Producttbl TABLE (id int, order_number varchar(20), product_id varchar(20), stock_cnt int, product_ship_flag VARCHAR(3))
INSERT INTO #Producttbl
SELECT 1,'001','SKU1', 1, 'Yes' union all
SELECT 2,'001','SKU2', 2, 'Yes' union all
SELECT 3,'001','SKU3', 1, 'No' union all
SELECT 4,'002','SKU1', 1, 'Yes' union all
SELECT 5,'002','SKU2', 2, 'Yes' union all
SELECT 6,'003','SKU1', 1, 'No' union all
SELECT 7,'003','SKU2', 2, 'No'
SELECT *
FROM
#Producttbl P
JOIN (
SELECT order_number, Flag=MIN(product_ship_flag)
--product_ship_flag is
---"YES" : for all the products of same the order_number
--If any of the product_ship_flag is "No" then the whole order_number should not be in the output.
--If all product_ship_flag as "No" then should not be in the output.
FROM
#Producttbl
GROUP BY
order_number
)S ON
S.order_number=P.order_number
WHERE
S.Flag='Yes'
see result below:
A left join could be handy in this case.
DECLARE #ProducttblTEST TABLE (id int, order_number varchar(20), product_id
varchar(20), stock_cnt int, product_ship_flag VARCHAR(3))
INSERT INTO #ProducttblTEST
SELECT 1,'001','SKU1', 1, 'Yes' union all
SELECT 2,'001','SKU2', 2, 'Yes' union all
SELECT 3,'001','SKU3', 1, 'No' union all
SELECT 4,'002','SKU1', 1, 'Yes' union all
SELECT 5,'002','SKU2', 2, 'Yes' union all
SELECT 6,'003','SKU1', 1, 'No' union all
SELECT 7,'003','SKU2', 2, 'No'
select * from #ProducttblTEST a
left join (select * from #ProducttblTEST where product_ship_flag = 'no') b on
a.order_number = b.order_number
where a.product_ship_flag = 'yes' and b.order_number is null

Calculating using Variables in MYSQL query

hope you can help, this is driving me up the wall
I need to calculate the percentage of times a question has been failed, but this needs to be narrowed down by the geographical area, and product these questions are being asked against.
I have :
$CA002 = "( SELECT ROUND(100 * (SELECT count(CA002Result) from Data_Table where (CA002Result='Fail'))/count(CA002Result),2) from Data_Table) AS 'CA002 %'";
Which 'works' but just calculates against the whole set of records as an 'overall'
I'm trying :
$CA001 = "( SELECT ROUND(100 * (SELECT count(CA001Result) from Data_Table where (CA001Result='Fail' AND Area ='$Area'))/count(CA001Result) from Data_Table WHERE (Area='$Area'),2) AS 'CA001 %'";
And Also :
$CA001 = "( SELECT ROUND(100 * (SELECT count(CA001Result ) from Data_Table where (CA001Result='Fail' AND Product='$product' AND Area='$Area'))
/ count(CA001Result WHERE Product = '$product' AND Area='$Area'),2) from Data_Table) AS 'CA001 %'";
and am just getting errors no matter what I try, I just can't seem to work out what I need to put where.
Any great GREATLY apprteciated, thankyou.
Try this
//Filter by Area
create table t( id int, answer varchar(10),Area varchar(10));
insert into t select 1 , 'pass' , 'Area1';
insert into t select 2 , 'pass' , 'Area1';
insert into t select 3 , 'fail' , 'Area1';
insert into t select 4 , 'fail' , 'Area1';
insert into t select 5 , 'fail' , 'Area1';
insert into t select 6 , 'fail' , 'Area2';
SELECT
(x.TotalFailedAnswerRecord * 100) /y.TotalRecord AS Fail_percent
FROM
( SELECT Area,TotalFailedAnswerRecord = COUNT(answer)
FROM t
WHERE answer='fail' AND Area = 'Area1'
GROUP BY Area
)x
INNER JOIN
( SELECT Area,TotalRecord = COUNT(answer)
FROM t
WHERE Area = 'Area1'
GROUP BY Area
)y ON x.Area =y.Area
//Result
Fail_percent
-------------
60
//Filter by Area,Product
create table t( id int, answer varchar(10),Area varchar(10),Product varchar(10));
insert into t select 1 , 'pass' , 'Area1' ,'Product1';
insert into t select 2 , 'fail' , 'Area1' ,'Product1';
insert into t select 3 , 'fail' , 'Area1' ,'Product1';
insert into t select 4 , 'fail' , 'Area1' ,'Product1';
insert into t select 5 , 'fail' , 'Area1' ,'Product2';
insert into t select 6 , 'fail' , 'Area2' ,'Product2';
SELECT
(x.TotalFailedAnswerRecord * 100) /y.TotalRecord AS Fail_percent
FROM
( SELECT Area,Product,TotalFailedAnswerRecord = COUNT(answer)
FROM t
WHERE answer='fail' AND Area = 'Area1' AND Product = 'Product1'
GROUP BY Area,Product
)x
INNER JOIN
( SELECT Area,Product,TotalRecord = COUNT(answer)
FROM t
WHERE Area = 'Area1' AND Product = 'Product1'
GROUP BY Area,Product
)y ON x.Area =y.Area AND x.Product = y.Product
//Result
Fail_percent
-------------
75
Hope this helps