Getting sub products from same table - sql-server

I have two tables, table1 has end products and product parts, table2 has a mapping between table1.productid and partsid. i.e.
table1
--------------------------------------------
productid descrip code cost ....etc
1235 product A 07 12.5 ......
789 labor 03 2.5 ....
839 part1 03 5 ....
and table2 looks like
table2
--------------------------------------------
productid partsID quantity
1235 789 1
1235 839 2
2341 2315 2
.....
I need to select the end product that meets specific code and go pull up the parts from the part table and display like below:
Resuls
--------------------------------------------
productid descrip code partsID cost ....etc
1235 product A 07 789 2.5 ......
1235 product A 03 839 5 ....
.......
Basically for each end product, line up the parts to the right and cost and all other details associated with the parts and not the end product.
Appreciate any help with this.

Could you not join the Two tables across ProductID field:
SELECT * FROM
dbo.TABLE1 o INNER JOIN
dbo.TABLE2 t ON o.ProductId = t.ProductId
WHERE o.code = 7
OR o.code = 3
etc ... whatever additional criteria you need
If you also need to Join the partsID you could say
AND o.PartId = t.partsId

It looks like you want to get something like this query, but I'm not sure about the code=07, you've specified in the example. Probably the code must be 03 for both parts.
SELECT
prd.productid,
prd.descrip,
prt.code,
prdprt.partsID,
prt.cost,
....etc
FROM table1 prd
JOIN table2 prdprt ON prd.productid=prdprt.productid
JOIN table1 prt ON prdprt.partsID=prt.productid
WHERE prd.code in ('07', ...othecodes) --if you filter by product's code
OR prt.code in ('03', ...othecodes) --if you filter by parts's code

Related

SQL: insert total count row after joining table

The first step is to join staff and customer together. The second step is to count the distinct product_id. My target is to add the total(sum) field under the result table.
Thanks.
staff
staff_ID Name cust_id
1 Tom 101
1 Tom 101
1 Tom 105
2 Peter 102
2 Peter 104
3 Billy 103
customer
cust_id product_id
101 A1
102 A2
103 A3
104 A4
105 A5
My work:
SELECT a.staff_name,COUNT(DISTINCT a.product_id)
FROM (SELECT distinct a.staff_id, a.staff_name, a.cust_id
FROM staff)a
LEFT JOIN customer b ON a.cust_id=b.cust_id
GROUPBY a.staff_name
What I want is to add the total column below the count.
Name count
Tom 2
Peter 2
Billy 1
Total 5
Update:
Regarding the "Total", as #MatBailie correctly pointed out in the comments:
The aggregate of multiple COUNT(DISTINCT) rows CAN NOT be guaranteed to be summable. If two staff members share the same product_id the summary value will be LESS THAN the sum of its members.
So for this sample data set:
db<>fiddle here
cust_id
product_id
101
A1
102
A2
103
A3
104
A4 <== Same product
105
A5
105
A4 <== Same product
Using GROUP BY ROLLUP yields a "Total" value of 5:
SELECT COALESCE(a.staff_name, 'Total') AS Staff_Name
, COUNT(DISTINCT b.product_id) AS [Count]
FROM staff a LEFT JOIN customer b ON a.cust_id=b.cust_id
GROUP BY ROLLUP (a.staff_name);
Results:
Staff_Name
Count
Billy
1
Peter
2
Tom
3
Total
5 **
Whereas calculating a simple sum of the totals, yields a "Total" value of 6. So just be aware of the difference.
Staff_Name
Count
Billy
1
Peter
2
Tom
3
Total
6 **
Original (Wrong Answer):
Can't remember where I saw this answer, but ... assuming Staff_Name is never null, you could use GROUP BY ROLLUP to obtain the total. That said calculating grand totals is usually more of a front-end job.
SELECT COALESCE(a.staff_name, 'Total') AS Staff_Name
, COUNT(DISTINCT b.product_id) AS [Count]
FROM staff a LEFT JOIN customer b ON a.cust_id=b.cust_id
GROUP BY ROLLUP (a.staff_name);
Try this one:
SELECT s.staff_name, COUNT(DISTINCT b.product_id), SUM(count) Total
FROM staff s
INNER JOIN customer b ON b.cust_id = s.cust_id
GROUP BY s.staff_name

SQL Server select join detect if common column between two tables are different

I am trying to write a function to check between two tables which have a common column with the same name and ID values.
Table 1: CompanyRecords
CompanyRecordsID CompanyId CompanyName CompanyProcessID
-----------------------------------------------------------
1 222 Sears 123
2 333 JCPenny 456
Table 2: JointCompanies
JointCompaniesID CompanyId CompanyName ComanyProcessID
-----------------------------------------------------------
3 222 KMart 123
4 444 Walmart 001
They both use the same foreign key CompanyProcessID with value 123.
How do I write a select statement when it is passed the CompanyProcessID to tell if the CompanyId has changed for the same CompanyProcessId.
I assume it is a join between the two tables with WHERE CompanyProcessID
Thanks for any help.
Is this what you want?
select max(case when cr.name = jc.name then 0 else 1 end) as name_not_same
from CompanyRecords cr join
JointCompanies jc
on cr.ComanyProcessID = jc.ComanyProcessID
where cr.ComanyProcessID = ?

SQL Server query involving subqueries - performance issues

I have three tables:
Table 1: | dbo.pc_a21a22 |
batchNbr Other columns...
-------- ----------------
12345
12346
12347
Table 2: | dbo.outcome |
passageId record
---------- ---------
00003 200
00003 9
00004 7
Table 3: | dbo.passage |
passageId passageTime batchNbr
---------- ------------- ---------
00001 2015.01.01 12345
00002 2016.01.01 12345
00003 2017.01.01 12345
00004 2018.01.01 12346
What I want to do: for each batchNbr in Table 1 get first its latest passageTime and the corresponding passageID from Table 3. With that passageID, get the relevant rows in Table 2 and establish whether any of these rows contains the record 200. Per passageId there are at most 2 records in Table 2
What is the most efficient way to do this?
I have already created a query that works, but it's awfully slow and thus unfit for tables with millions of rows. Any suggestion on how to either change the query or do it another way? Altering the table structure is not an option, I only have read rights to the database.
My current solution (slow):
SELECT TOP 50000
a.batchNbr,
CAST ( CASE WHEN 200 in (SELECT TOP 2 record FROM dbo.outcome where passageId in (
SELECT SubqueryResults.passageId From (SELECT Top 1 passageId FROM dbo.passage pass WHERE pass.batchNbr = a.batchNbr ORDER BY passageTime Desc) SubqueryResults
)
) then 1 else 0 end as bit) as KGT_IO_END
FROM dbo.pc_a21a22 a
The desired output is:
batchNbr 200present
--------- ----------
12345 1
12346 0
I suggest you use table joining rather than subqueries.
select
a.*, b.*
from
dbo.table1 a
join
dbo.table2 b on a.id = b.id
where
/*your where clause for filtering*/
EDIT:
You could use this as a reference Join vs. sub-query
Try this
SELECT TOP 50000 a.*, (CASE WHEN b.record = 200 THEN 1 ELSE 0 END) AS
KGT_IO_END
FROM dbo.Test1 AS a
LEFT OUTER JOIN
(SELECT record, p.batchNbr
FROM dbo.Test2 AS o
LEFT OUTER JOIN (SELECT MAX(passageId) AS passageId, batchNbr FROM
dbo.Test3 GROUP BY batchNbr) AS p ON o.passageId = p.passageId
) AS b ON a.batchNbr = b.batchNbr;
The MAX subquery is to get the latest passageId by batchNbr.
However, your example won't get the record 200, since the passageId of the record with 200 is 00001, while the latest passageId of the batchNbr 12345 is 00003.
I used LEFT OUTER JOIN since the passageId from Table2 no longer match any of the latest passageId from Table3. The resulting subquery would have no records to join to Table1. Therefore INNER JOIN would not show any records from your example data.
Output from your example data:
batchNbr KGT_IO_END
12345 0
12346 0
12347 0
Output if we change the passageId of record 200 to 00003 (the latest for 12345)
batchNbr KGT_IO_END
12345 1
12346 0
12347 0

SQL query to get all the data from different tables with same id

Sorry if this is too elemental but I cannot work it out. Don’t know how to search information on it either:
I have three tables:
Provider
id_provider name
---------- -----------
100 John
101 Sam
102 Peter
Contact
id_contact RowNo Email
---------- ----------- ----------------
100 1 john#work.com
100 2 john#gmail.com
101 1 sam#work.com
101 2 sam#yahoo.com
Product
Id_product RowNo Product
---------- ----------- ------------------------
100 1 John’s 1st product
100 2 John’s 2nd product
101 1 Sam’s 1st product
101 2 Sam’s 2nd product
101 3 Sam’s 3rd product
I need a query to show all the data from the three tables like this:
Id name id_contact RowNo Email Id_Product RowNo Product
100 John 100 1 john#work.com 100 1 John’s 1st product
100 John 100 2 john#gmail.com 100 2 John’s 2st product
101 Sam 101 1 sam#work.com 101 1 Sam's 1st product
101 Sam 101 2 sam#yahoo.com 101 2 Sam's 2nd product
101 Sam null null null 101 3 Sam's 3rd product
102 Peter null null null null null null
I am trying all the joins I know but I cannot make it work.
Thanks a lot
You can use the following query:
SELECT t1.id_provider AS Id, t1.name,
t2.id_contact, t2.cRowNo, t2.Email,
t2.Id_product, t2.Product
FROM Provider AS t1
LEFT JOIN (
SELECT COALESCE(id_contact, id_product) AS id,
c.id_contact, c.RowNo AS cRowNo, c.Email,
p.Id_product, p.Product, p.RowNo AS pRowNo
FROM Contact AS c
FULL JOIN Product AS p ON p.id_product = c.id_contact AND p.RowNo = c.RowNo
) AS t2 ON t1.id_provider = t2.id
The query does a FULL JOIN between Contact and Product tables and joins the table derived from the FULL JOIN to Provider table.
A FULL JOIN is required because we cannot know beforehand which of the two tables, Contact or Product, contains the most rows for each id.
select *
from Provider P1
left join Contact C2
on C2.id_contact = P1.id_provider
left join Product P2
on P2.id_product = P1.id_provider
SELECT prov.*,
c.*,
prod.*
FROM PROVIDER prov
LEFT JOIN Product prod ON prod.id_product = prov.id_provider
LEFT JOIN Contact c ON prov.id_provider = c.id_contact
AND prod.RowNo = c.RowNo
use left joins but join provider to product first then to contact
SQL Fiddle Demo

Joining two SQL tables based on the equality of few columns

I am trying to Create a SQL View by joining two SQL tables and return only the lowest value from second table and all the rows from first table similar to left join.
My problem can be clearly explained with the below example.
Table1
Id Product Grade Term Bid Offer
100 ABC A Q1 10 20
101 ABC A Q1 5 25
102 XYZ A Q2 25 30
103 XYZ B Q2 20 30
Table2
Id Product Grade Term TradeValue
1 ABC A Q1 100
2 ABC A Q1 95
3 XYZ B Q2 100
In the above data I want to join Table1 and Table2 when ever the columns Product,Grade and Term from both the tables are equal and return all the rows from Table1 while joining the lowest Value of the column TradeValue from Table2 to the first record of the match and making TradeValue as NULL for other rows of the resultant View and the resultant View should have the Id of Table2 as LTID
So the resultant SQL View should be
RESULT
Id Product Grade Term Bid Offer TradeValue LTID
100 ABC A Q1 10 20 95 2
101 ABC A Q1 5 25 NULL 2
102 XYZ A Q2 25 30 NULL NULL
103 XYZ B Q2 20 30 100 3
I tried using the following query
CREATE VIEW [dbo].[ViewCC]
AS
SELECT
a.Id,a.Product,a.Grade,a.Term,a.Bid,a.Offer,
b.TradeValue
FROM Table1 AS a
left JOIN (SELECT Product,Grade,Term,MIN(TradeValue) TradeValue from Table2 Group by Product,Grade,Term,) AS b
ON b.Product=a.Product
and b.Grade=a.Grade
and b.Term=a.Term
GO
The above Query returned the following data which is apt to the query I wrote but that is not what I was trying to get
Id Product Grade Term Bid Offer TradeValue
100 ABC A Q1 10 20 95
101 ABC A Q1 5 25 95 --This should be null
102 XYZ A Q2 25 30 NULL
103 XYZ B Q2 20 30 100
As we can see minimum value of TradeValue being assigned to all matching rows in Table1 and also I was not able to return Id As LTID from Table2 as I have issues with group by clause as I cannot group it by b.Id as it returns too many rows.
May I know a better way to deal with this?
You need a row number attached to each record from Table1, so that the requirement of only joining the first record from each group of Table1 can be fulfilled:
CREATE VIEW [dbo].[ViewCC]
AS
SELECT a.Id, a.Product, a.Grade, a.Term, a.Bid, a.Offer,
b.TradeValue, b.Id AS LTID
FROM (
SELECT *, ROW_NUMBER() OVER(PARTITION BY Product, Grade, Term ORDER BY Id) AS rn
FROM Table1
) a
OUTER APPLY (
SELECT TOP 1 CASE WHEN rn = 1 THEN TradeValue
ELSE NULL
END AS TradeValue, Id
FROM Table2
WHERE Product=a.Product AND Grade=a.Grade AND Term=a.Term
ORDER BY TradeValue) b
GO
OUTER APPLY returns a table expression containing either the matching record from Table2 with the lowest TradeValue, or NULL if no matching record exists.

Resources