SQL Case Reference - sql

Using the code below (thank you #BHouse), I am attempting to adjust "ECOMMERCE" selling price to reflect "ENFIELD" selling price. As you can see from results, I am getting multiple entries.
Results can been seen here
SELECT
T1.STRTRADECODE AS [STORE],
T1.LINTITEMNUMBER AS [SKU],
CASE WHEN T1.STRTRADECODE = 'ECOMMERCE' THEN T2.CURNORMALSELL ELSE T1.CURNORMALSELL END AS [SELLINGPRICE]
FROM DAILYSALES T1
LEFT JOIN DAILYSALES T2 ON T1.LINTITEMNUMBER = T2.LINTITEMNUMBER AND T1.STRTRADECODE <> T2.STRTRADECODE
WHERE
T1.DTMTRADEDATE >= '2018-01-02 00:00:00'
AND T1.STRSALETYPE = 'I'
AND T1.STRTRADECODE IN ('ECOMMERCE', 'ENFIELD')
AND T1.LINTITEMNUMBER = '18760'
GROUP BY
T1.STRTRADECODE,
T1.LINTITEMNUMBER,
T1.CURNORMALSELL,
T2.CURNORMALSELL
ORDER BY
T1.STRTRADECODE DESC
Any help will be much appreciated.

Added Sku to the table , matching Sku and different store numbers will retrieve selling value for store2.
This query will help u, to use values matching another store
SELECT T1.STRTRADECODE AS [STORE], T1.LINTITEMNUMBER AS [SKU], T2.CURNORMALSELL AS [SELLINGPRICE]
FROM DAILYSALES T1
INNER JOIN (
SELECT *
FROM DAILYSALES
WHERE name = 'enfield'
) t2
ON t1.sku = t2.sku
WHERE T1.DTMTRADEDATE >= '2018-01-02 00:00:00' AND T1.STRSALETYPE = 'I' AND T1.STRTRADECODE IN (
'ECOMMERCE'
,'ENFIELD'
) AND T1.LINTITEMNUMBER = '18760'
ORDER BY T1.STRTRADECODE DESC
sample:
DECLARE #testtable TABLE (id INT identity(1, 1), name VARCHAR(100), sellingPrice FLOAT, sku BIGINT)
INSERT INTO #testtable (name, sellingPrice, sku)
SELECT 'Enfield', '60.50', '16043853021'
UNION
SELECT 'Ecommerce', '190.50', '16043853021'
UNION
SELECT 'Enfield', '120.45', '06062829018'
UNION
SELECT 'Ecommerce', '180.45', '06062829018'
;
select distinct t.id,t.name,t.sku,t2.sellingPrice
from #testtable t Inner join (select * from #testtable where name = 'enfield') t2
on t.sku = t2.sku

Related

I need to join 2 databases, with 2 tables each

Dears,
I have an SQL problem. I need to join 2 databases, with 2 tables each. I have the pictures of the tables of the databases here. Thank you very much for your helps.
With a UNION ALL you can get 1 combined resultset from 2 selects.
Then you can group that and SUM the amounts per date.
So you're probably looking for something like this:
select
q.ID,
q.Name,
nullif(sum(case when q.Date = '2018-05-01' then q.Amount end), 0) as "5/1/2018",
nullif(sum(case when q.Date = '2018-05-02' then q.Amount end), 0) as "5/2/2018"
from
(
select u1.ID, u1.Name, a1.Date, a1.Amount
from DB1.Table1 AS u1
join DB1.Table2 AS a1 on (a1.ID = u1.ID and a1.Amount is not null)
where a1.Date IN ('2018-05-01', '2018-05-02')
union all -- combines the results of the 2 selects into one resultset
select u2.ID, u2.Name, a2.Date, a2.Amount
from DB2.Table1 AS u2
join DB2.Table2 AS a2 on (a2.ID = u2.ID and a2.Amount is not null)
where a2.Date IN ('2018-05-01', '2018-05-02')
) AS q
group by q.ID, q.Name
order by q.ID;
An alternative is to JOIN them all up.
select
coalesce(a1.ID, a2.ID) as ID,
max(coalesce(u1.Name, u2.Name)) as Name,
max(case
when coalesce(a1.Date, a2.Date) = '2018-05-01'
and coalesce(a1.Amount, a2.Amount) is not null
then coalesce(a1.Amount, 0) + coalesce(a2.Amount, 0)
end) as "5/1/2018",
max(case
when coalesce(a1.Date, a2.Date) = '2018-05-02'
and coalesce(a1.Amount, a2.Amount) is not null
then coalesce(a1.Amount, 0) + coalesce(a2.Amount, 0)
end) as "5/2/2018"
from DB1.Table2 AS a1
full join DB2.Table2 AS a2 on (a2.ID = a1.ID and a2.Date = a1.Date)
left join DB1.Table1 AS u1 on (u1.ID = a1.ID)
left join DB2.Table1 AS u2 on (u2.ID = a2.ID)
where coalesce(a1.Date, a2.Date) IN ('2018-05-01', '2018-05-02')
group by coalesce(a1.ID, a2.ID)
order by coalesce(a1.ID, a2.ID);
But then note that this way, that there's an assumption that the two Table2 have a uniqueness on (ID, Date)
T-Sql test data:
declare #DB1_Table1 table (id int, Name varchar(30));
declare #DB2_Table1 table (id int, Name varchar(30));
declare #DB1_Table2 table (id int, [Date] date, Amount decimal(8,2));
declare #DB2_Table2 table (id int, [Date] date, Amount decimal(8,2));
insert into #DB1_Table1 (id, Name) values (1,'Susan'),(2,'Juan'),(3,'Tracy'),(4,'Jenny'),(5,'Bill');
insert into #DB2_Table1 (id, Name) values (1,'Susan'),(2,'Juan'),(3,'Tracy'),(4,'Jenny'),(5,'Bill');
insert into #DB1_Table2 (id, [Date], Amount) values
(1,'2018-05-01',20),(2,'2018-05-01',null),(3,'2018-05-01',30),(4,'2018-05-01',50),(5,'2018-05-01',null),
(1,'2018-05-02',15),(2,'2018-05-02',40),(3,'2018-05-02',25),(4,'2018-05-02',8),(5,'2018-05-02',null);
insert into #DB2_Table2 (id, [Date], Amount) values
(1,'2018-05-01',null),(2,'2018-05-01',15),(3,'2018-05-01',20),(4,'2018-05-01',10),(5,'2018-05-01',null),
(1,'2018-05-02',15),(2,'2018-05-02',30),(3,'2018-05-02',35),(4,'2018-05-02',null),(5,'2018-05-02',30);

SQL for a Join that contains a condition within one of the join conditions

I have a requirement to do a left join between two tables. TableA is a transactional table while TableB contains reference data. The logical rule for my join is as follow:
SELECT *
FROM
TableA a
LEFT JOIN TableB b
ON a.ItemCode = b.ItemCode
AND a.ItemType = b.ItemType
AND b.FundID = 1 (but if no match found use b.FundID = 99)
The last join condition, the part in brackets, is what I'm having trouble with.
EDIT: Some clarification - If no match is found on ItemCode & ItemType & FundID = 1 then I want to join on ItemCode & ItemType & FundID = 99. Also TableB might have two records that match on both ItemCode and ItemType with one record having a FundID = 1 and the second record having FundID = 2. I that case I only want the record with FundID = 1.
What would be the most efficient way to write this query?
The only thing I can come up with is to execute the query twice, once with FundID = 1 and then with FundID = 99. Then use a set operator to return all the records form the first query and only records from the second query that does not exist in the first one. The code will not be pretty and it does not seem efficient either.
Thanks for your ideas in advance.
Marius
If i do understand your requirement correctly, this should gives you what you want
SELECT *
FROM
TableA a
OUTER APPLY
(
SELECT TOP 1 *
FROM TableB b
WHERE a.ItemCode = b.ItemCode
AND a.ItemType = b.ItemType
AND b.FundID IN (1, 99)
ORDER BY b.FundID
) b
You can change the query to
AND b.FundID IN (1,99)
or
AND (b.FundID = 1 or b.FundID = 99)
This is the best solution I have received so far. Thanks to #HABO (see the comments section of my question).
Add a column to create a Row_Number() partitioned on ItemType and ItemCode and ordered by FundId, then use only the results with row number 1
For posterity:
-- Sample data.
declare #TableA as Table ( AId Int Identity, ItemCode VarChar(20), ItemType VarChar(20) );
declare #TableB as Table ( BId Int Identity, ItemCode VarChar(20), ItemType VarChar(20), FundId Int );
insert into #TableA ( ItemCode, ItemType ) values
( 'Nemo', 'Fish' ), ( 'Blinky', 'Fish' ), ( 'Muddy Mudskipper', 'Fish' ),
( 'Hammer', 'Tool' ), ( 'Screwdriver', 'Tool' ), ( 'Politician', 'Tool' ),
( 'Grape Nehi', 'Beverage' ), ( 'Screwdriver', 'Beverage' );
insert into #TableB ( ItemCode, ItemType, FundId ) values
( 'Blinky', 'Fish', 1 ), ( 'Muddy Mudskipper', 'Fish', 2 ),
( 'Hammer', 'Tool', 1 ), ( 'Screwdriver', 'Tool', 99 ),
( 'Politician', 'Tool', 1 ), ( 'Politician', 'Tool', 99 ),
( 'Grape Nehi', 'Beverage', 42 ), ( 'Screwdriver', 'Beverage', 1 );
select * from #TableA;
select * from #TableB;
-- Do the deed.
with JoinWithRanking as (
select A.AId, A.ItemCode, A.ItemType, B.BId, B.FundId,
Row_Number() over ( partition by A.ItemCode, A.ItemType order by B.FundId ) as RN
from #TableA as A left outer join
#TableB as B on B.ItemCode = A.ItemCode and B.ItemType = A.ItemType and
B.FundId in ( 1, 99 )
)
select AId, ItemCode, ItemType, BId, FundId
from JoinWithRanking
where RN = 1;

Add column that counts times value occurs in results

I have a query with 5 columns. I want to add 1 column that defines the number of times the value in column 2 (ItemCode) occurs in the results.
This is my query:
SELECT
Items.Description_0 AS [Items.Description],
Items.ItemCode,
warehouse_location,
Stock.Quantity AS StockQty,
Stock.warehouse
FROM
((SELECT gbkmut.artcode, gbkmut.warehouse, ISNULL(gbkmut.warehouse_location,'') AS warehouse_location,
SUM(gbkmut.aantal) AS Quantity FROM gbkmut
INNER JOIN Items ON Items.ItemCode = gbkmut.artcode
INNER JOIN voorrd ON voorrd.artcode=gbkmut.artcode
AND voorrd.magcode=gbkmut.warehouse
INNER JOIN ItemUnits ON ItemUnits.Unit = Items.PackageDescription
WHERE gbkmut.reknr = Items.GLAccountDistribution
AND (( gbkmut.transtype IN ('N', 'C', 'P', 'X')
AND gbkmut.datum BETWEEN {d '2000-01-09'} AND {d '2031-02-08'} ) )
AND (gbkmut.warehouse='MAG1' )
AND Items.Type IN ('S','B')
AND NOT (Items.GLAccountAsset IS NOT NULL AND Items.IsSerialNumberItem=1) AND NOT (Items.Type = 'S' AND ItemUnits.UnitType = 'T')
GROUP BY gbkmut.artcode, gbkmut.warehouse, ISNULL(gbkmut.warehouse_location,'')
HAVING SUM(gbkmut.aantal) > 0)) Stock
INNER JOIN Items ON Items.ItemCode=Stock.artcode
WHERE Items.ItemCode like '10.27021%'
ORDER BY Items.ItemCode
Lazy version, use a common table expression (cte):
with cte as
(
[your huge select]
)
select t1.*, t2.codecount
from cte t1
join (select ItemCode, count(*) as codecount from cte group by ItemCode) as t2
ON t2.ItemCode = t1.ItemCode

Transforming a column into a row

I have the following query:
SELECT DISTINCT
T0.DocNum, T0.Status, T1.ItemCode, T2.ItemName,
T1.PlannedQty, T0.PlannedQty AS 'Net Quantity'
FROM
OWOR T0
INNER JOIN
WOR1 T1 ON T0.DocEntry = T1.DocEntry
INNER JOIN
OITM T2 ON T0.ItemCode = T2.ItemCode
WHERE
T0.Status = 'L' AND
T1.ItemCode IN ('BYP/RM/001', 'BYP/RM/002', 'BYP/RM/003', 'BYP/RM/004','BILLET') AND
T2.ItmsGrpCod = 111 AND
(T0.PostDate BETWEEN (SELECT Dateadd(month, Datediff(month, 0, {?EndDate}), 0)) AND {?EndDate})
that returns data like:
Explanation:
To make 10 MM steel bars, billets are used as raw materials. Any ItemCode 'BYP%' is part of solid wastage. The net quantity for every DocNum is the amount of 'MM' steel produced by weight. For example, for DocNum 348, the following are used as inputs:
However for that DocNum, 147.359 of 10 MM steel was produced, meaning the missing 3.52 (150.879 - 147.359) is burned loss (not solid).
How do I modify the query such that for each DocNum, the query returns:
See the SQL code below.
declare #input_tbl table ( doc_num int, item_code varchar(15), item_name varchar(10), planned_qty decimal(15,9), net_qty decimal(15,9) )
declare #ouput_tbl table ( doc_num int, item varchar(15), name varchar(10), quantity decimal(15,9) )
-- Inserting sample data shown by you. You will have to replace this with your 1st query.
insert into #input_tbl values (348, 'BILLET' , '10MM', 154.629000, 147.359000)
insert into #input_tbl values (348, 'BYP/RM/001' , '10MM', -1.008000, 147.359000)
insert into #input_tbl values (348, 'BYP/RM/003' , '10MM', -1.569000, 147.359000)
insert into #input_tbl values (348, 'BYP/RM/004' , '10MM', -1.173000, 147.359000)
-- This stores unique doc numbers from input data
declare #doc_tbl table ( id int identity(1,1), doc_num int )
insert into #doc_tbl select distinct doc_num from #input_tbl
-- Loop through each unique doc number in the input data
declare #doc_ctr int = 1
declare #max_doc_id int = (select max(id) from #doc_tbl)
while #doc_ctr <= #max_doc_id
begin
declare #doc_num int
declare #planned_qty_total decimal(15,9)
declare #net_qty decimal(15,9)
declare #burned_loss decimal(15,9)
declare #item_name varchar(15)
select #doc_num = doc_num from #doc_tbl where id = #doc_ctr
select #planned_qty_total = sum(planned_qty) from #input_tbl where doc_num = #doc_num
select distinct #item_name = item_name, #net_qty = net_qty from #input_tbl where doc_num = #doc_num
select #burned_loss = #planned_qty_total - #net_qty
-- 'Union' is also fine but that won't sort the records as desired
insert into #ouput_tbl select doc_num, item_code, item_name, planned_qty from #input_tbl
insert into #ouput_tbl select #doc_num, 'BurnLoss', #item_name, #burned_loss * -1
insert into #ouput_tbl select #doc_num, 'Net', #item_name, #net_qty
set #doc_ctr = #doc_ctr + 1
end
select * from #ouput_tbl
Ouput:
docnum item name quantity
348 BILLET 10MM 154.629000000
348 BYP/RM/001 10MM -1.008000000
348 BYP/RM/003 10MM -1.569000000
348 BYP/RM/004 10MM -1.173000000
348 BurnLoss 10MM -3.520000000
348 Net 10MM 147.359000000
You should use a UNION. I guess
(/*your original query*/)
UNION
SELECT DISTINCT
T0.DocNum, T0.Status, 'BurnLoss' AS ItemCode, T2.ItemName,
SUM(T1.PlannedQuantity)-T0.PlannedQuantity AS PlannedQuantity, T0.PlannedQuantity AS 'Net Quantity'
FROM
OWOR T0
INNER JOIN
WOR1 T1 ON T0.DocEntry = T1.DocEntry
INNER JOIN
OITM T2 ON T0.ItemCode = T2.ItemCode
WHERE
T0.Status = 'L' AND
T1.ItemCode IN ('BYP/RM/001', 'BYP/RM/002', 'BYP/RM/003', 'BYP/RM/004','BILLET') AND
T2.ItmsGrpCod = 111 AND
(T0.PostDate BETWEEN (SELECT Dateadd(month, Datediff(month, 0, {?EndDate}), 0)) AND {?EndDate})
GROUP BY T0.DocNum
UNION
SELECT DISTINCT
T0.DocNum, T0.Status, 'Net' AS ItemCode, T2.ItemName,
T0.PlannedQuantity, T0.PlannedQuantity AS 'Net Quantity'
FROM
OWOR T0
INNER JOIN
WOR1 T1 ON T0.DocEntry = T1.DocEntry
INNER JOIN
OITM T2 ON T0.ItemCode = T2.ItemCode
WHERE
T0.Status = 'L' AND
T1.ItemCode IN ('BYP/RM/001', 'BYP/RM/002', 'BYP/RM/003', 'BYP/RM/004','BILLET') AND
T2.ItmsGrpCod = 111 AND
(T0.PostDate BETWEEN (SELECT Dateadd(month, Datediff(month, 0, {?EndDate}), 0)) AND {?EndDate})
GROUP BY T0.DocNum
should work, although it might even be better to do some of this in a language like PHP, because now every bit of information is fetched twice (and the query becomes two times as long).
Use a UNION ALL to combine your original query with a second BurnLoss query of GROUP BY T0.DocuNum that computes SUM(T1.PlannedQty) - T0.PlannedQty and a third Net query to show T0.PlannedQty

MSSQL Inner Join on Concatenated Column

I'm not a DBA so please don't yell at me. Trying to do an inner join and Group By using a concatenated column. The ON statement is producing a syntax error. I do not have access to the original tables and am trying to normalize this into another table, I know its ugly. Not overly worried about performance, just need to work. Cant use functions either.
SELECT DISTINCT A.[carrier_code],[carrier_name], [carrier_grouping], A.[collector_name], [dataset_loaded], [docnum], [envoy_payer_id], [loc], [market], [master_payor_grouping], [plan_class], [plan_name], A.[resp_ins],A.[resp_ind], A.[resp_payor_grouping], A.[Resp_Plan_Type], A.[rspphone], A.[state], A.[sys],A.[resp_ins]+A.[resp_payor_grouping]+A.[carrier_code]+A.[state]+A.[Collector_Name] as ExtId
FROM [Table1] A
INNER JOIN
(SELECT [resp_ins]+[resp_payor_grouping]+[carrier_code]+[state]+[Collector_Name] as Extid
FROM [Table1]
WHERE [resp_ind] = 'Insurance'
GROUP BY [resp_ins]+[resp_payor_grouping]+[carrier_code]+[state]+[Collector_Name]) B
ON A.[resp_ins]+A.[resp_payor_grouping]+A.[carrier_code]+A.[state]+A.[Collector_Name] = B.[resp_ins]+B.[resp_payor_grouping]+B.[carrier_code]+B.[state]+B.[Collector_Name];
My ON and Group By statements are eventually the primary key in new table.
Your alias B hasn't columns as you mentioned. It has just on column Extid.
SELECT DISTINCT A.[carrier_code],[carrier_name], [carrier_grouping], A.[collector_name], [dataset_loaded], [docnum], [envoy_payer_id], [loc], [market], [master_payor_grouping], [plan_class], [plan_name], A.[resp_ins],A.[resp_ind], A.[resp_payor_grouping], A.[Resp_Plan_Type], A.[rspphone], A.[state], A.[sys],A.[resp_ins]+A.[resp_payor_grouping]+A.[carrier_code]+A.[state]+A.[Collector_Name] as ExtId
FROM [Table1] A
INNER JOIN
(SELECT [resp_ins]+[resp_payor_grouping]+[carrier_code]+[state]+[Collector_Name] as Extid
FROM [Table1]
WHERE [resp_ind] = 'Insurance'
GROUP BY [resp_ins]+[resp_payor_grouping]+[carrier_code]+[state]+[Collector_Name]) B
ON A.[resp_ins]+A.[resp_payor_grouping]+A.[carrier_code]+A.[state]+A.[Collector_Name] = B.Extid;
Try this, I didn't put all the column in result, you can manage yourself.
select A.*
from
(
select [carrier_code],[carrier_name], [sys],[resp_ins]+[resp_payor_grouping]+[carrier_code]+[state]+[Collector_Name] as ExtId
FROM [Table1]
) A
inner join
(
select distinct Extid
from
(
SELECT [resp_ins]+[resp_payor_grouping]+[carrier_code]+[state]+[Collector_Name] as ExtId
FROM [Table1]
WHERE [resp_ind] = 'Insurance'
) ins
) B on (A.ExtId = B.ExtId)
You don't need to concatenate the values - you can GROUP BY and JOIN on multiple columns.
SELECT DISTINCT
...
FROM
[Table1] A
INNER JOIN
(
SELECT
[resp_ins],
[resp_payor_grouping],
[carrier_code],
[state],
[Collector_Name]
FROM
[Table1]
WHERE
[resp_ind] = 'Insurance'
GROUP BY
[resp_ins],
[resp_payor_grouping],
[carrier_code],
[state],
[Collector_Name]
) B
ON
(
A.[resp_ins] = B.[resp_ins]
Or
(A.[resp_ins] Is Null And B.[resp_ins] Is Null)
)
And
(
A.[resp_payor_grouping] = B.[resp_payor_grouping]
Or
(A.[resp_payor_grouping] Is Null And B.[resp_payor_grouping] Is Null)
)
And
(
A.[carrier_code] = B.[carrier_code]
Or
(A.[carrier_code] Is Null And B.[carrier_code] Is Null)
)
And
(
A.[state] = B.[state]
Or
(A.[state] Is Null And B.[state] Is Null)
)
And
(
A.[Collector_Name] = B.[Collector_Name]
Or
(A.[Collector_Name] Is Null And B.[Collector_Name] Is Null)
)
;