Click here to Skip to main content
15,868,340 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Dear experts, I'm lost, please help me.

I have a table with BOM Positions:
BomId   MaterialId   MaterialQuantity   Note
-----   ----------   ----------------   -----
Bom_A   Mat_A        20                 BOM1
Bom_A   Mat_B        30                 BOM1
Bom_B   Mat_A        20                 BOM2
Bom_B   Mat_B        35                 BOM2
Bom_C   Mat_A        20                 BOM1
Bom_C   Mat_B        30                 BOM1
Bom_D   Mat_A        10                 BOM3
Bom_D   Mat_B        20                 BOM3
Bom_D   Mat_C        30                 BOM3
Bom_E   Mat_A        10                 BOM3
Bom_E   Mat_B        20                 BOM3
Bom_E   Mat_C        30                 BOM3

Based on that table I like to select distinct the equal BOMs.
Equal here means the BomDetails have same material in same quantities.

Note: The column 'Note' is only for the explanation here and does not exists in my db.

Therefore the result I'm looking for is something like this:
MaterialId	 MaterialQuantity   BOMGRP   BOMCOUNT
----------   ----------------   ------   ---------
Mat_A        20                 1        2
Mat_B        30                 1        2
Mat_A        20                 2        1
Mat_B        35                 2        1
Mat_A        10                 3        2
Mat_B        20                 3        2
Mat_C        30                 3        2

'BOMGRP' should be a dynamically created Id.
'BOMCOUNT' would be nice, but I can live without it

I hope my question makes sense.
Thank you very much in advance.

What I have tried:

I tried to solve it with the help of ChatGPT, but without success.
Btw. I'm on MS SQL Server 2014 :(
[Edit]: Upgraded to MS SQL Server 2019 :)

DROP TABLE BomPositions;
CREATE TABLE BomPositions
(
   BomId             VARCHAR(30),
   MaterialId        VARCHAR(30),
   MaterialQuantity  DOUBLE PRECISION,
   Note				 VARCHAR(30)
);


INSERT INTO BomPositions(BomId, MaterialId, MaterialQuantity, Note) VALUES
   ('Bom_A', 'Mat_A', 20, 'BOM1'),
   ('Bom_A', 'Mat_B', 30, 'BOM1'),
   ('Bom_B', 'Mat_A', 20, 'BOM2'),
   ('Bom_B', 'Mat_B', 35, 'BOM2'),
   ('Bom_C', 'Mat_A', 20, 'BOM1'),
   ('Bom_C', 'Mat_B', 30, 'BOM1'),
   ('Bom_D', 'Mat_A', 10, 'BOM3'),
   ('Bom_D', 'Mat_B', 20, 'BOM3'),
   ('Bom_D', 'Mat_C', 30, 'BOM3'),
   ('Bom_E', 'Mat_A', 10, 'BOM3'),
   ('Bom_E', 'Mat_B', 20, 'BOM3'),
   ('Bom_E', 'Mat_C', 30, 'BOM3');

SELECT * FROM BomPositions ORDER BY BomId, MaterialId;
Posted
Updated 19hrs ago
v6

1 solution

The query should look like -
SQL
WITH BOMGroups AS (
    SELECT DISTINCT BomId, ROW_NUMBER() OVER (ORDER BY BomId) AS BOMGRP
    FROM BomPositions
),
BOMCounts AS (
    SELECT BomId, COUNT(DISTINCT MaterialId) AS BOMCOUNT
    FROM BomPositions
    GROUP BY BomId
)
SELECT MaterialId,
       MaterialQuantity,
       BOMGRP,
       BOMCOUNT
FROM (
    SELECT MaterialId,
           MAX(MaterialQuantity) AS MaterialQuantity,
           BomId,
           ROW_NUMBER() OVER (PARTITION BY BomId ORDER BY MaterialId) AS RowNum
    FROM BomPositions
    GROUP BY MaterialId, BomId
) AS SubQuery
JOIN BOMGroups ON SubQuery.BomId = BOMGroups.BomId
JOIN BOMCounts ON SubQuery.BomId = BOMCounts.BomId
ORDER BY BOMGRP, MaterialId;


I have not tested though.

[EDIT]
SQL
WITH BOMGroups AS (
    SELECT
        BomId,
        ROW_NUMBER() OVER (ORDER BY BomId) AS BOMGRP
    FROM
        (SELECT DISTINCT BomId FROM BomPositions) AS DistinctBomIds
),
BOMCounts AS (
    SELECT
        BomId,
        COUNT(DISTINCT MaterialId) AS BOMCOUNT
    FROM
        BomPositions
    GROUP BY
        BomId
),
MaterialRanks AS (
    SELECT
        BomId,
        MaterialId,
        MAX(MaterialQuantity) AS MaterialQuantity,
        DENSE_RANK() OVER (PARTITION BY BomId ORDER BY MaterialId) AS MaterialRank
    FROM
        BomPositions
    GROUP BY
        BomId,
        MaterialId
)
SELECT
    MaterialId,
    MaterialQuantity,
    BOMGRP,
    BOMCOUNT
FROM
    MaterialRanks
    JOIN BOMGroups ON MaterialRanks.BomId = BOMGroups.BomId
    JOIN BOMCounts ON MaterialRanks.BomId = BOMCounts.BomId
ORDER BY
    BOMGRP,
    MaterialRank;

[END EDIT]
 
Share this answer
 
v2
Comments
0x01AA 16hrs ago    
Thank you for your interest .
My 5 for your help, it gives me a direction and ideas.

The result is unfortunatelly not what I expect.
It ends in 12 Groups wehere I expect 3 and also 30 reuslt lines instead of 7.
Anyway wow! Without testing, no syntax error in your sql statement ;)

Btw. My current appraoch is to create a 'Set Id' with the help of 'STRING_AGG'. It works, but I don' like it. It is far away from SQL's set approach.
Andre Oosthuizen 16hrs ago    
Ouch, let me test the query and see where I got it wrong, should have returned the expected 7 lines... :)

"Anyway wow! Without testing, no syntax error in your sql statement ;)" - I have a little self written helper file that checks for syntax errors as I have been bitten before. :)
Andre Oosthuizen 15hrs ago    
I played with the query, still not 100% but much closer. I think the issue is with the 'MaterialRank' if you want to look into this. The result now is -

MaterialId	MaterialQuantity	BOMGRP	BOMCOUNT
Mat_A	20	1	2
Mat_B	30	1	2
Mat_A	20	2	2
Mat_B	35	2	2
Mat_A	20	3	2
Mat_B	30	3	2
Mat_A	10	4	3
Mat_B	20	4	3
Mat_C	30	4	3
Mat_A	10	5	3
Mat_B	20	5	3
Mat_C	30	5	3


See fiddle here to play on - BOM Fiddle[^]
0x01AA 14hrs ago    
Thank you very much again! Unfortunately I can't upvote again :)
At the moment, I let the question as 'not solved' to have a chance, that others will participate.
Later on, I will accept your answer, because you gave me very good inputs.
0x01AA 13hrs ago    
FYI, below my ugly approach,at least to determine the Groups with a thing like SetId.

As mentioned, I don't like it. It works, but I assume only by chance. This because it is not possible to have a 'order by' in the select statement for the 'STRING_AGG' and furthermore it is simply ugly and has many restrictions and does not really follows the set theory on which SQL is based.

WITH Bom AS (
SELECT  DISTINCT
	BomId
  FROM BomPositions
),
BomSetId AS (
   SELECT
      Bom.BomId,
	  (SELECT STRING_AGG(BomPos.MaterialId + '_' + FORMAT(BomPos.MaterialQuantity, 'N2'), ',') 
      FROM BomPositions BomPos 
	  WHERE  (BomPos.BomId = Bom.BomId)
	  AS SetId
   FROM Bom 
)

SELECT 
	DISTINCT SetId 
FROM BomSetId
ORDER BY SetId;

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900