Deleting rows in sql rows based on pair value - sql

I have SQL test table as below:
Item
Doc_No
Code
Line_Item
1
abc1234
101
01
2
abc1234
102
01
3
def5678
101
01
4
def5678
102
01
5
ghi1234
101
01
6
ghi1234
101
02
7
jkl5678
101
01
I am trying to eliminate rows when duplicate values of "Doc_No" has pair values of "101" and "102" in "Code" column e.g abc1234 and def5678.
At the same time I want to maintain duplicate values of "Doc_No" without the pair value of "101" and "102" in "Code" column e.g. ghi1234. Final output as below:
Item
Doc_No
Code
Line_item
5
ghi1234
101
01
6
ghi1234
101
02
7
jkl5678
101
01
I tried to get the rows with duplicate values and exclude them but this will wrongly exclude "ghi1234" and not the final output table I want.
SELECT
a.*,
b.Count_Item
FROM dbo.test AS a
LEFT JOIN
(SELECT Doc_No, COUNT(*) AS Count_Item
FROM dbo.test
GROUP BY Doc_No
HAVING COUNT(*) > 1) AS b
ON a.Doc_No = b.Doc_No
WHERE b.Count_Item < 2
Item
Doc_No
Code
Line_Item
Count_Item
7
jkl5678
101
01
1
Can somebody help me with this?

Building on your construct:
SELECT a.*
FROM dbo.test a LEFT JOIN
(SELECT Doc_No, COUNT(*) AS Count_Item
FROM dbo.test
WHERE code IN (101, 102)
GROUP BY Doc_No
) b
ON a.Doc_No = b.Doc_No
WHERE b.Count_Item < 2 OR Count_Item IS NULL;
Note: This assumes that codes are not duplicated for a doc.

What about this:
select *
from test
group by Doc_No, Line_Item
having count(*) = 1
or this:
select *
from test
where Doc_No not in (
select Doc_No
from test
join test as test2 using (Doc_No)
where test.Code = 101 and test2.Code = 102
);

Related

SQl calculate column value based on reference table

I want to select a column value based on the reference table in SQL Server.
These are the tables:
Tbl1
id Cost LineNo
-----------------------
1 10 01
2 20 02
3 30 03
Tbl2
id LineNo MaterialCost
--- ----- -----------
1 03 50
I want to calculate Totalcost (as line no * Materialcost) from tbl2 if there is a matching lineno in tbl2 from tbl1 else get the TotalCost (lineno * Cost) from tbl1
Below is the output I want
id Cost LineNo TotalCost
----------------------- ---------
1 10 01 10
2 20 02 40
3 30 03 150
You can use LEFT JOIN and coalesce as follows:
select t1.*, (t1.lineNo * coalesce(t2.materialcost, t1.cost)) as total
from table1 t1
left join table2 t2 on t1.lineno = t2.lineno
In sql server, you can use this:
select Tbl1.id,
Tbl1.Cost,
Tbl1.LineNo,
Tbl1.LineNo * ISNULL(tbl2.MaterialCost, Tbl1.Cost)
from Tbl1
left join Tbl2
on Tbl1.LineNo = Tbl2.LineNo

Using Group By as part of a where clause

I'm trying to eliminate certain records from a dataset using SQL Server. The title of my post may be inaccurate, as a better solution may exist than what I have in mind.
In my query, I am selecting from Table A, and the rows that I want to end up with should meet the following criteria:
All rows where A.ItemNumber = B.ItemNumber
All rows where A.ItemNumber <> B.ItemNumber AND that row's Task value does not have another row that meets criteria #1.
So for the below example:
Gives us ItemNumber 102, 104, 106 rows.
Gives us ItemNumber 105 row.
100, 101 are removed from dataset because their Task (1) is associated with Table B at ItemNumber 102. Same for 103 with Task (2) being associated at ItemNumber 104.
Table A
Task ItemNumber
1 100
1 101
1 102
2 103
2 104
3 105
4 106
Table B
ItemNumber Data
102 aaa
104 bbb
106 ccc
My initial thought was to load Table A into a temp table, LEFT JOIN with Table B, and DELETE FROM {temp table} WHERE (data IS NULL AND {insert some kind of grouping logic here}). But I have been completely unable to figure out a grouping logic that will work for the problem. I spent the weekend hoping a solution would come to me, but am now giving in and seeking advice.
With a CTE that meets the 1st condition and UNION ALL to return the rest of the rows:
with cte as (
select a.*
from TableA a
where exists (select 1 from TableB where ItemNumber = a.ItemNumber)
)
select * from cte
union all
select a.* from TableA a
where not exists (select 1 from cte where Task = a.Task)
order by Task
See the demo.
Results:
Task ItemNumber
1 102
2 104
3 105
4 106
One way to phrase this puts all the filtering logic in the where clause:
select a.*
from tablea a
where exists (select 1
from tableb b
where b.itemnumber = a.itemnumber
) or
not exists (select 1
from tableb b2 join
tablea a2
on b2.itemnumber = a2.itemnumber
where a2.task = a.task
);
SELECT *
FROM TABLEA AS A
LEFT JOIN TABLEB AS B ON A.ItemNumber = B.ItemNumber
WHERE B.ItemNumber IS NOT NULL -- critera 1
OR (B.ItemNumber IS NULL AND B.ItemNumber NOT IN
(SELECT A.ItemNumber
FROM TABLEA AS A
JOIN TABLEB AS B ON A.ItemNumber = B.ItemNumber)) -- criteria 2

Oralce SQL nested or inner join when you need to compare the same table but different rows with unique ID values

I'm having a trouble writing a query in ORACLE. I have a Table that contains values. for example:
ID quantity partID
123 50 10
100 20 10
100 30 11
123 null 8
456 null 100
789 25 123
456 50 9
I want to get all rows that has same ID but quantities to be 50 and null (exact same pairs of 50 and null only). for the given example I would like to get:
ID quantity partID
123 50 10
123 null 8
456 50 9
456 null 100
I tried inner join but it doesn't provide the exact output as expected.
You may try :
select ID, quantity, partID
from tab
where ID in
(
select ID
from tab
where nvl(quantity,50)=50
group by ID
having count(distinct nvl(quantity,0) )>1
);
ID QUANTITY PARTID
123 50 10
123 (null) 8
456 (null) 100
456 50 9
SQL Fiddle Demo
P.S. you may get the same results by commenting out having count(ID)=2 also but for those cases there may not exist one of 50 or null for values of quantity.
You can use exists:
select t.*
from t
where (t.quantity = 50 and
exists (select 1 from t t2 where t2.id = t.id and t2.partid = t.partid and t2.value is null)
) or
(t.quantity is null and
exists (select 1 from t t2 where t2.id = t.id and t2.partid = t.partid and t2.value = 50)
) ;

Update a null value cell with an ID and the table is related to 3 others

I have a Table that is joined from other tables. I want to update a null value in this Table by a specific number series. Below is the illustration:
The code for the Table which is called List_Codes
SELECT mlk.MLK_CODE
FROM zpt
LEFT OUTER JOIN mes ON mes.ZPT_ID = zpt.ZPT_ID
LEFT OUTER JOIN zmlk ON zpt.ZPT_ID = zmlk.ZPT_ID
LEFT OUTER JOIN mlk ON zmlk.MLK_ID = mlk.MLK_ID
WHERE zpt.zpt_id IS NOT NULL
and zpt.zpt_meteringcode = '123456'
ORDER BY mes.MES_STATUS DESC
Now I want to update this specific row's mlk.MLK_CODE from null to '789'. I have located this row based on the zpt.zpt_meteringcode. Any suggestions plz?
The tables look like this, and the List_Code Table is the result of the above code
Mlk Table
Mlk_id Mlk_code
1 123
2 456
Zpt Table
Zpt_id Zpt_meteringcode
10 123456
20 987654
30 654321
40 147852
Zmlk Table
Zpt_id Mlk_id
20 1
30 2
List_Code Table
Zpt_id Zpt_meteringcode Mlk_id Mlk_code
10 123456
20 987654 1 123
30 654321 2 456
40 147852
I think you need two inserts and one update statements like this.
INSERT INTO mlk (mlk_code)
VALUES ( '789' ); -- Primary key is generated
.....
INSERT INTO zmlk (zpt_id,
mlk_id)
SELECT (SELECT zpt_id
FROM zpt
WHERE zpt_meteringcode = '123456'),
(SELECT mlk_id
FROM mlk
WHERE mlk_code = '789')
FROM dual;
....
UPDATE list_code
SET ( mlk_id, mlk_code ) = (SELECT mlk_id,
mlk_code
FROM mlk
WHERE mlk_code = '789')
WHERE zpt_meteringcode = '123456';

SQL - Find the Top Level Parent and Multiply Quantities

I have two tables which track part numbers as well as the hierarchy of assemblies.
Table: Config
ConfigNum AssemblyNum Qty
1 A 1
1 B 2
1 C 2
2 A 1
2 C 1
Table: SubAssembly
SubAssembly PartNum Qty
A AA 2
A BB 4
A CC 2
A DD 4
B EE 4
B FF 8
AA AAA 2
I would like to create a flat version of these tables which shows the ConfigNum (Top level parent) with all associated assembly and part numbers, for each ConfigNum in the Config table. The column Config.AssemblyNum is equivalent to SubAssembly.SubAssembly.
The Subassembly table shows the partent to child relation ship between parts. For example Assembly 'A' has a child assembly 'AA'. Since 'AA' exists in the SubAssembly Column is it self an assembly and as you can see it has a child part 'AAA'. 'AAA' does not exist in the SubAssemly columns therefore it is the last child in the series.
I would also like to have an accurate quantity count of each part based on multiplying of parent to child down the chain.
For example in the output:
(Total Qty of AAA) = (Qty A) x (Qty AA) x (Qty AAA)
4 = 1 x 2 x 2
Example Output table: (for Config 1)
ConfigNum SubAssembly PartNum TotalQty
1 A AA 2
1 A BB 4
1 A CC 2
1 A DD 4
1 B EE 8
1 B FF 16
1 A AAA 4
Any suggestion on how to complete this task would be greatly appreciated.
EDIT: I have been able to create this code based on suggestions made in the answers.
I am still having trouble getting the quantities to multiply down.
I have received the error "Types don't match between the anchor and the recursive part in column "PartQty" of recursive query "RCTE"."
;WITH RCTE (AssemblyNum, PartNum, PartQty, Lvl) AS
(
SELECT AssemblyNum, PartNum, PartQty, 1 AS Lvl
FROM SP_SubAssembly r1
WHERE EXISTS (SELECT * FROM SP_SubAssembly r2 WHERE r1.AssemblyNum = r2.PartNum)
UNION ALL
SELECT rh.AssemblyNum, rc.PartNum, (rc.PartQty * rh.PartQty), Lvl+1 AS Lvl
FROM dbo.SP_SubAssembly rh
INNER JOIN RCTE rc ON rh.PartNum = rc.AssemblyNum
)
SELECT CB.ID, CB.ConfigNum, CB.PartNum, CB.PartQty, r.AssemblyNum, r.PartNum, SUM(r.PartQty * COALESCE(CB.PartQty,1)) AS TotalQty
FROM SP_ConfigBOM CB
FULL OUTER JOIN RCTE r ON CB.PartNum = r.AssemblyNum
WHERE CB.ConfigNum IS NOT NULL
ORDER BY CB.ConfigNum
Thanks,
For this problem I think you must use a recursive query. In fact I think SubAssembly table should have some ProductID field other than SubAssembly to easily identify the main product that contains assemblies.
You can find a similar example in SLQ Server documentation.
Can check it here: http://rextester.com/FQYI80157
Change the Qty in Config table to change the final result.
create temp table t1 (cfg int, part varchar(10), qty int);
create temp table t2 (part varchar(10), sasm varchar(10), qty int);
insert into t1 values (1,'A',2);
insert into t2 values ('A','AA',2);
insert into t2 values ('A','BB',4);
insert into t2 values ('A','CC',2);
insert into t2 values ('A','DD',4);
insert into t2 values ('AA','AAA',2);
WITH cte(sasm, part, qty)
AS (
SELECT sasm, part, qty
FROM #t2 WHERE part = 'A'
UNION ALL
SELECT p.sasm, p.part, p.qty * pr.qty
FROM cte pr, #t2 p
WHERE p.part = pr.sasm
)
SELECT #t1.cfg, cte.part, cte.sasm, SUM(cte.qty * COALESCE(#t1.qty,1)) as total_quantity
FROM cte
left join #t1 on cte.part = #t1.part
GROUP BY #t1.cfg, cte.part, cte.sasm;
This is the result:
+------+------+----------------+
| part | sasm | total_quantity |
+------+------+----------------+
| A | AA | 4 |
+------+------+----------------+
| A | DD | 8 |
+------+------+----------------+
| AA | AAA | 4 |
+------+------+----------------+
| A | BB | 8 |
+------+------+----------------+
| A | CC | 4 |
+------+------+----------------+
insert into #Temp
SELECT A.[ConfigNum] ,
A.[AssemblyNum],
B.[PartNum],
A.[Qty],
A.QTY * B.Qty TotalQty
INTO #Temp
FROM [Config] A,
[SubAssembly] B
WHERE A.[AssemblyNum] = B.[SubAssembly]
SELECT A.[ConfigNum] ,
A.[AssemblyNum],
A.[PartNum],
A.[Qty],
A.TotalQty
FROM #Temp A
union
SELECT A.[ConfigNum] ,
A.[AssemblyNum],
B.[PartNum],
A.[Qty],
A.TotalQty * B.Qty
FROM #Temp A,
[SubAssembly] B
WHERE
A.[PartNum] = B.[SubAssembly]