Merge two nested sets into rows - sql

I'm given a nested set database which has the following reduced structure:
Bus its root table (B)
CL
CR
SL
SR
1
6
1
12
Compound table which represents levels of hierarchy with each level having different attributes (C)
Level 1 (C1)
CL
CR
SL
SR
C5
C6
1
6
1
12
NULL
test
Level 2 (C2a)
CL
CR
SL
SR
C5
C6
2
3
1
12
foo
NULL
and (C2b)
CL
CR
SL
SR
C5
C6
4
5
1
12
bar
NULL
Lastly S containing signals where S1 is it’s id.
S1
S2
2
0xFA
..
..
11
0x10
Then comes the tricky part:
I need to create a list of the 10 S table items with the complete path and hierarchical values up the tree.
So it would result in a list with values that look something like this
S
C
..
C
R
S2-values
C2a-values
..
C1-values
R
..
..
..
..
..
S11-values
C2a-values
..
C1-values
R
S2-values
C2b-values
..
C1-values
R
..
..
..
..
..
S11-values
C2b-values
..
C1-values
R
Any suggestion to loosen the knot in my brain is helpful.
What I tried so far is the following, which does not seem to work as it just crashes the machine:
select
*
from
signal s,
compound c
join (
select
bus.short_name,
cBase.dtype,
cBase.value,
cPdu.relative_bit_position,
cPdu.bit_length,
cPdu.left_signal,
cPdu.right_signal,
cSwp.switch_code
from
compound as cbase
left join compound as cPdu on
cPdu.dtype = 'P'
and cBase.left_compound < cPdu.left_compound
and cBase.right_compound > cPdu.right_compound
left join compound as cswp on
cSwp.dtype = 'SWP'
and cBase.left_compound < cSwp.left_compound
and cBase.right_compound > cSwp.right_compound
left join bus as bus on
bus.left_compound < cBase.left_compound
and bus.right_compound > cBase.right_compound
where
cBase.dType = 'CF') as res on s.id between res.left_signal and res.right_signal
In the above code I restricted the depth of the categories to 3 (cBase, cPdu, cSwp).
What I need is a generalized approach that can handle all depths.

Related

Get the records which don't match the condition

I have three tables that have data like this:
Table CON_MEMBER:
CONTAINER_DATA_BO
CONTAINER_NUMBER_BO
PARENT_REF_001
CHILD_REF_001
PARENT_REF_001
CHILD_REF_002
Table CON_DATA:
HANDLE
CONTAINER_NUMBER
CHILD_REF_001
CHILD_001
CHILD_REF_002
CHILD_002
Table CON_CUSTOM_DATA:
CONTAINER_DATA_BO
DATA_FIELD
DATA_ATTR
CHILD_REF_001
QTY
10
CHILD_REF_001
CLASS
CLASS 1
CHILD_REF_001
MAT
MAT 1
CHILD_REF_001
TYPE
BARREL
CHILD_REF_001
TRANSPORT
1
CHILD_REF_002
QTY
100
CHILD_REF_002
CLASS
CLASS 2
CHILD_REF_002
MAT
MAT 2
CHILD_REF_002
TYPE
DRUM
Now I have written a query that will get all the child container numbers against the parent container for which the CON_CUSTOM_DATA.TRANSPORT is not 1
SELECT DISTINCT
cd.CONTAINER_NUMBER
FROM
CON_MEMBER cm1
INNER JOIN
CON_MEMBER cm2 ON cm1.CONTAINER_NUMBER_BO = cm2.CONTAINER_DATA_BO
INNER JOIN
CON_DATA cd ON cd.HANDLE = cm1.CONTAINER_NUMBER_BO
LEFT JOIN
CON_CUSTOM_DATA ccd ON cd.HANDLE = ccd.CONTAINER_DATA_BO
WHERE
cm1.CONTAINER_DATA_BO = 'PARENT_REF_001'
AND ccd.DATA_ATTR <> '1'
But the query returns both the child "CHILD_002" as well as "CHILD_001". What is am expecting from above query is to get the Child Container Number "CHILD_002", Since for this container TRANSPORT is not 1.
Please help me achieve this output.
Thanking you in advance.
You could try something like this
SELECT DISTINCT cd.CONTAINER_NUMBER
FROM CON_MEMBER cm
JOIN CON_DATA cd ON cm.CONTAINER_NUMBER_BO=cd.HANDLE
WHERE NOT EXISTS (SELECT 1
FROM CON_CUSTOM_DATA ccd
WHERE cd.HANDLE = ccd.CONTAINER_DATA_BO
AND ccd.DATA_FIELD='TRANSPORT'
AND ccd.DATA_ATTR=1);

Combining SQL Tables for one source of information

I'm trying to combine 3 different tables into one single row in a query but having some problems. Currently I have four tables; PaintSched, Painted_Log, Paint_Defect, and Paint_Inspection.
PaintSched - Single entry, when scheduler just schedules some parts to be painted
LOT QTY
1 150
2 100
Painted_Log - The paint department then takes the lot and says how many they were able to paint
LOT(FK) QTYPainted
1 145
2 100
Paint_Defect - Master List of defects for paint inspection after parts have been painted. We hand inspect all of our parts that we paint for quality.
DID Defect
1 Scratch
2 Paint Run
Paint_Inspection - Everytime a defect is found the inspector hits a correlating button and the following gets logged. Lot is FK and DID stands for Defect ID from Paint_Defect. QTY is always 1
Lot(FK) DID(FK) QTY
1 1 1
1 1 1
1 2 1
1 1 1
2 2 1
1 2 1
2 1 1
What I'm trying to get is the following output:
Lot Sched Painted Scratch Paint Run
1 150 145 3 2
2 100 100 1 1
I've tried the following to no avail:
SELECT PaintSched.Scheduled, PaintSched.Lot, PaintSched.qty, PaintSched.Is_Painted, Painted_Log.falloff
FROM PaintSched
INNER JOIN Painted_Log ON PaintSched.Lot = Painted_Log.lot
INNER JOIN MPA_Desc ON MPA_Desc.MPAID = PaintSched.MPAID
inner JOIN (
SELECT lot, sum(Paint_Inspection.qty) as seds
FROM Paint_Inspection
WHERE Paint_Inspection.Status = '1'
) AS seeds ON PaintSched.Lot = Paint_Inspection.Lot
SELECT
PS.Lot,
PS.Qty Sched,
Painted,
Scratch,
PaintRun
FROM PaintSched PS
LEFT JOIN (SELECT
Lot,
SUM(QTYPainted) Painted
FROM Painted_Log GROUP BY Lot) PL
ON PS.Lot = PL.Lot
LEFT JOIN (SELECT
Lot,
SUM(CASE WHEN DID = 1 THEN 1 ELSE 0 END) Scratch,
SUM(CASE WHEN DID = 2 THEN 1 ELSE 0 END) PaintRun
FROM Paint_Inspection GROUP BY Lot) PI
ON PS.Lot = PI.Lot
Try that in SQL Fiddle
The code above uses conditional sum to roll up the defect count by type before joining that to the lot id. If you have more than 2 statuses, you will need to update the above code accordingly.
Two things:
You should have a group by in the subquery
When you alias the subquery, you don't join it properly
See the edits to your query below:
SELECT
PaintSched.Scheduled,
PaintSched.Lot,
PaintSched.qty,
PaintSched.Is_Painted,
Painted_Log.falloff
FROM PaintSched
INNER JOIN Painted_Log ON PaintSched.Lot = Painted_Log.lot
INNER JOIN MPA_Desc ON MPA_Desc.MPAID = PaintSched.MPAID
INNER JOIN (
SELECT lot, sum(Paint_Inspection.qty) as seds
FROM Paint_Inspection
WHERE Paint_Inspection.Status = '1'
GROUP BY Paint_Inspection.lot -- Missing GROUP BY
) AS seeds
ON PaintSched.Lot = seeds.Lot

SQL join in the where statement

I am currently having to use two different queries to get back the results that I'm looking for. I have tried combining the two queries together, but that ends with me getting a large amount of extra(duplicates) data that I do not need. Below I have the working query listed.
SELECT p1.note as Itemcode,
order.ID as OrderNo,
piece1.ID As Piece1,
piece2.ID As Piece2,
i1.count as Unit,
unit.count as TotalUnits,
i1.rack as RackNo,
p1.EndDate as Piece1Finish,
p2.EndDate as Piece2Finish,
unit.group as BatchNo
FROM db.dbo.unit
JOIN db.dbo.order on order.entry_ID = unit.entry_ID
JOIN db.dbo.piece piece1 on piece1.ID_piece = unit.ID_piece_1
JOIN db.dbo.piece piece2 on piece2.ID_piece = unit.ID_piece_3
JOIN db.dbo.items i1 on i1.ID_unit = unit.ID_unit
JOIN db.dbo.items i2 on i2.ID_unit = unit.ID_unit
JOIN db.dbo.items i3 on i3.ID_unit = unit.ID_unit
JOIN db.dbo.items i4 on i4.ID_unit = unit.ID_unit
JOIN db.dbo.process p1 on p1.ID_process = i1.ID_process
JOIN db.dbo.process p2 on p2.ID_process = i2.ID_process
JOIN db.dbo.process p3 on p3.ID_process = i3.ID_process
JOIN db.dbo.process p4 on p4.ID_process = i4.ID_process
WHERE p1.note like '12A%'
and p1.ID_pieceorder = '1'
and p1.ID_job = '150'
and p2.ID_pieceorder = '3'
and p2.ID_job = '150'
and i1.count = i2.count
and i1.count = i3.count
and i1.count = i4.count
and i1.rack = i2.rack
and p1.note = p2.note
and i1.status = '1'
and i2.status = '1'
and p3.ID_pieceorder = '0'
and p4.ID_pieceorder = '2'
and p3.ID_job = '153'
and p4.ID_job = '151'
and i3.status = '0'
and i4.status = '0'
and order.status <> '4'
ORDER BY OrderNo
This query works fine. The second set of data I query to find adds the following information
SELECT ...(same as above)
FROM ...(same as above plus the following)
JOIN db.dbo.items i5 on i5.ID_unit = unit.ID_unit
JOIN db.dbo.items i6 on i6.ID_unit = unit.ID_unit
JOIN db.dbo.process p5 on p5.ID_process = i5.ID_process
JOIN db.dbo.process p6 on p6.ID_process = i6.ID_process
WHERE p1.note like '12B%'
and ... (same as above plus the following)...
and p5.ID_pieceorder = '1'
and p5.ID_job = '152'
and p6.ID_pieceorder = '3'
and p6.ID_job = '152'
and i5.status = '1'
and i6.status = '1'
and i1.count = i5.count
and i1.count = i6.count
When I try to make a combined query, the table joins of i5, i6, p5, and p6 produce a massive amount of duplicated results for p1.note like '12A%' due to it not needing the fields. Is there a method where I can initiate a join in the WHERE statement so that it will only use those two tables when p1.note like '12B%'? Something along the lines of
SELECT ....
FROM ....
WHERE (p1.note like '12A%'
or
(p1.note like '12B%'
and p5.ID_pieceorder = '1'
and p5.ID_job = '152'
and p6.ID_pieceorder = '3'
and p6.ID_job = '152'
and i5.status = '1'
and i6.status = '1'
and i1.count = i5.count
and i1.count = i6.count
(JOIN db.dbo.items i5 on i5.ID_unit = unit.ID_unit
JOIN db.dbo.items i6 on i6.ID_unit = unit.ID_unit
JOIN db.dbo.process p5 on p5.ID_process = i5.ID_process
JOIN db.dbo.process p6 on p6.ID_process = i6.ID_process)))
I know that the syntax above will not work, but I am looking for a method similar to that.
**EDIT FOR TABLE STRUCTURE requested by DRapp
I'm going to fill out the results I get with ID_unit 782327
-db.dbo.items-
-ID_item- -ID_process- -count- -status- -rack- -ID_unit-
628335 782328 1 0 25 782327
628336 782330 1 1 25 782327
628337 782331 1 1 25 782327
628338 782333 1 0 25 782327
628339 782335 1 1 25 782327
628340 782336 1 1 25 782327
628341 782337 1 0 25 782327
-db.dbo.process-
-ID_process- -ID_unit- -ID_pieceorder- -ID_job- -sequence-
782328 782327 0 50 1
782329 782327 1 5305 1
782330 782327 1 150 1
782331 782327 1 152 2
782332 782327 2 5408 2
782333 782327 2 151 1
782334 782327 3 5308 3
782335 782327 3 150 1
782336 782327 3 152 2
782337 782327 0 153 4
-db.dbo.unit-
-ID_unit- -status- -ID_piece_1- -ID_piece_2--ID_piece_3--ID_product-count
782327 2 5305 5408 5308 50 1
db.dbo.items contains a unique key for each "item" that goes into a part, it contains the corresponding process code, the "count" field, the "status" of each "item", the rack for each "item", and the unit ID of each "ITEM".
db.dbo.process contains the unique key for each "process", the ID_unit, ID_pieceorder, ID_job, and the sequence. Each unit starts with ID_pieceorder 0 which is establishing the product type, then ID_piece 1 for the first piece, etc..
db.dbo.unit contains the unique key for each "unit", the codes for all its pieces, the status of the unit, and count which is the number of units.
db.dbo.piece is a table with the master list of codes on it.
-ID_Piece- -Desc-
5305 14black
5408 14blue
150 Cut
The point of needing 6 processes is as follows
p1 & i1: Making sure the Piece is Piece 1, is process 150, and that process 150 is complete
p2 & i2: Making sure the piece is piece 2, is process 150, and that process 150 is complete
p3 & i3: Making sure it the completion process, 153, is not completed.
p4 & i4: making sure the connector process, 152, isn't completed(hasn't connected the two pieces).
p5 & i5: some pieces require extra work done, this checks and makes sure that process, 152, is completed on piece 1.
P6 & i6: The same as p5 & i5 but for piece 2.
if you don't want duplicates use a Union in between them, move you order by clause to the bottom of the second one. Make sure you select columns are in the same order in both statements.
select (your columns)
From (tables and joins)
where (your where)
UNION
select (your columns)
From (tables and joins)
where (your where)
order by
Per chatroom clarification, I have come up with the the following for you to start with and minimally adjust as needed.
SELECT
u.id_unit,
u.count as TotalUnits,
u.group as BatchNo,
p1.ID_PieceOrder as Piece1Order,
p1Cut.ID_Process as Piece1CutProcessID,
i1Cut.Count as Item1CutCount,
i1Cut.Status as Item1CutStatus,
p1Tamp.ID_PieceOrder as Piece1OrderTampered,
p1Tamp.ID_Process as Piece1TamperedProcessID,
i1Tamp.Count as Item1TamperedCount,
i1Tamp.Status as Item1TamperedStatus,
p2.ID_PieceOrder as Piece2Order,
p2Cut.ID_Process as Piece2CutProcessID,
i2Cut.Count as Item2CutCount,
i2Cut.Status as Item2CutStatus,
p2Tamp.ID_PieceOrder as Piece2OrderTampered,
p2Tamp.ID_Process as Piece2TamperedProcessID,
i2Tamp.Count as Item2TamperedCount,
i2Tamp.Status as Item2TamperedStatus,
pSpacer.ID_PieceOrder as SpacerPieceOrder,
iSpacer.Count as SpacerCount,
iSpacer.Status as SpacerStatus,
pSealed.ID_PieceOrder as SealedPieceOrder,
iSealed.Count as SealedCount,
iSealed.Status as SealedStatus
FROM
db.dbo.unit u
JOIN Process p1
ON u.ID_Unit = p1.ID_Unit
AND u.ID_Piece_1 = p1.ID_Job
JOIN Process p1Cut -- ALL PIECES MUST BE CUT first
ON p1.ID_Unit = p1Cut.ID_Unit
AND p1.ID_PieceOrder = p1Cut.ID_PieceOrder
AND p1Cut.ID_Job = 150
JOIN Items i1Cut
ON p1Cut.id_process = i1Cut.id_process
LEFT JOIN Process p1Tamp -- NOT ALL PIECES MUST BE TEMPERED
ON p1Cut.ID_Unit = p1Tamp.ID_Unit
AND p1Cut.ID_PieceOrder = p1Tamp.ID_PieceOrder
AND p1Tamp.ID_Job = 152
LEFT JOIN Items i1Tamp
ON p1Tamp.id_process = i1Tamp.id_process
JOIN Process p2
ON u.ID_Unit = p2.ID_Unit
AND u.ID_Piece_3 = p2.ID_Job
JOIN Process p2Cut -- ALL PIECES MUST BE CUT first
ON p2.ID_Unit = p2Cut.ID_Unit
AND p2.ID_PieceOrder = p2Cut.ID_PieceOrder
AND p2Cut.ID_Job = 150
JOIN Items i2Cut
ON p2Cut.id_process = i2Cut.id_process
LEFT JOIN Process p2Tamp -- NOT ALL PIECES MUST BE TEMPERED
ON p2Cut.ID_Unit = p2Tamp.ID_Unit
AND p2Cut.ID_PieceOrder = p2Tamp.ID_PieceOrder
AND p2Tamp.ID_Job = 152
LEFT JOIN Items i2Tamp
ON p2Tamp.id_process = i2Tamp.id_process
LEFT JOIN Process PSpacer
ON u.ID_Unit = PSpacer.ID_Unit
AND u.ID_Job = 151
LEFT JOIN Items ISpacer
ON PSpacer.ID_Process = ISpacer.ID_Process
LEFT JOIN Process PSealed
ON u.ID_Unit = PSealed.ID_Unit
AND u.ID_Job = 153
LEFT JOIN Items ISealed
ON PSealed.ID_Process = ISealed.ID_Process
WHERE
u.ID_Unit IN (782327, 782328, 782329 )
-- just a sample of 3 unit IDs to test concept of the revised query structure
I started at the unit table. From that, I am taking each piece down its respective path... First to get the piece, then from the piece, its CUT which will always be required. From the CUT to its ITEM status record which will always exist. From the CUT, I am then looking for a TAMPERED status for the same piece order. Since not all glass needs to be tampered, I have this as a LEFT-JOIN. I then LEFT-JOIN to the tampered's item record by the process id.
I do the same for the SECOND piece.
Then, a LEFT-JOIN to see IF there is a spacing required (can change to JOIN if spacer is ALWAYS required)
Finally, a LEFT-JOIN on the job completed entry. Again, don't know if all the entries are pre-filled in up-front for ALL stages of the process vs not.
Notice my alias name reference from P1 for the process for piece 1, then the p1Cut to i1Cut, to p1Tamp to i1Tamp. So now, instead of generic p1-p6, I have context to the process or item. Additionally, I just grabbed all the columns from the respective piece, cut, tampered, spacer and sealed steps with clear column names. If you don't want something you can always remove it, but with this, you SHOULD never get any duplicates per a single UNIT.
I did not add the join to the order or piece tables respectively. I don't know if piece is really needed unless you had other columns such as the P1.Name, but your table structure dump showed the description.
Since I did not add any other qualifiers, you should get the entire status of a single UNIT in one row. I would adjust the WHERE clause to pick a range of a few units you can test and confirm the context. THEN, adjust the where clause to look for your other criteria such as an item count = another or not, or piece within your '%a%' context or not. However, I THINK this will get you well on your way.
Something like this
LEFT JOIN db.dbo.process p1
on p1.ID_process = i1.ID_process
and p1.note like '12A%'
and p1.ID_pieceorder = '1'
and p1.ID_job = '150'
and p2.ID_pieceorder = '3'
and p2.ID_job = '150'
and i1.count = i2.count
and i1.count = i3.count
and i1.count = i4.count
and i1.rack = i2.rack
and p1.note = p2.note
and i1.status = '1'
and i2.status = '1'
and p3.ID_pieceorder = '0'
and p4.ID_pieceorder = '2'
and p3.ID_job = '153'
and p4.ID_job = '151'
LEFT JOIN db.dbo.items i5
on i5.ID_unit = unit.ID_unit
and p1.note like '12B%'
and i5.status = '1'

How to SUM an AS column in SQL

I have the following code...
SELECT WF.Word, WF.Frequency, WW.Weight, (WF.Frequency * WW.Weight) AS Product
FROM WF
INNER JOIN WW ON WW.Word = WF.word
Which outputs the following...
WORD | FREQUENCY | WEIGHT | PRODUCT
Fat 3 2 6
Ugly 2 4 8
Stupid 1 7 7
I also want to sum the product column at the same time. I understand how to sum an existing column but unsure how to sum a column i'm creating.
SELECT SUM(WF.Frequency * WW.Weight) AS Product
FROM WF
INNER JOIN WW ON WW.Word = WF.word
SELECT WF.Word, SUM(WF.Frequency) Frequency, SUM(WW.Weight) Weight, SUM(WF.Frequency * WW.Weight) AS Product
FROM WF
INNER JOIN WW ON WW.Word = WF.word
GROUP BY WF.Word
;
SELECT SUM(WF.Frequency * WW.Weight) Product
FROM WF
INNER JOIN
WW ON WW.Word = WF.word

Adding a new column in this SQL Query?

I am querying data from the WIP and Employee tables:
WIP
Id,Name
Employee
Id,Name,Orgnization
Joining both I can query:
select w.ID,e.Organization,w.ConsultantName,e.OrganizationID, w.ConsultantID
from vwWIPRecords w
inner join vwEmployees e on w.ConsultantID=e.ID;
Resutls:
1 VHAA Web User 1 1
2 VHAA NZ RP 1 3
3 VHAA Ghom Mure 1 2
4 VHAA Ghom Mure 1 2
Requirment:
In query add anther column which will concatenate and group by e.Organization and e.ConsultantName but it will be only for first unique record. For next (where name and organization is same) it will not show anything. This column will show unique Consultants of a company. Please see record number 3 and 4 in second example.
1 VHAAWeb User 1 1
2 VHAANZ RP 1 3
3 VHAAGhom Mure 1 2
4 1 2
Thanks a lot for your help
Here is a start. The final column is a flag indicating the row should be blank. Let me know if this works for you so far and I can help further.
select w.ID,e.Organization, w.ConsultantName,
e.OrganizationID, w.ConsultantID, CASE WHEN D.Dup > 1 AND D.ID <> w.ID THEN 'Y'
ELSE 'N' END As HideMe
from vwWIPRecords w
inner join vwEmployees e on w.ConsultantID=e.ID
inner join
(
select MIN(w.ID) As ID, e.Organization,w.ConsultantName,
e.OrganizationID, w.ConsultantID, COUNT(*) AS Dup
from vwWIPRecords w
inner join vwEmployees e on w.ConsultantID=e.ID
) D
ON D.Organization = w.Organization
AND D.ConsultantName = w.ConsultantName
AND D.OrganizationID = w.OrganizationID
AND D.ConsultantID = w.ConsultantID