SQL server Left join with child tables and get the table name - sql

Let's assume we have a table Instrument with child tables Equity and Bond having a foreign key InstrumentId. Each instrument has a unique record in one of the child tables.
Is it possible to make a view using left joins to see all the instrument with a column containing the table name in which the record is present ?
SELECT Instrument.InstrumentId, Instrument.Name, ***CHILD_TABLE_NAME***
FROM Instrument
LEFT OUTER JOIN
Equity ON Equity.InstrumentId = Instrument.InstrumentId
LEFT OUTER JOIN
Bond ON SBond.InstrumentId = Instrument.InstrumentId
An alternative is to make an union of inner joins:
SELECT instrumentId, Name, instrumentType
FROM
(SELECT Instrument.instrumentId, Name, 'Equity' as instrumentType FROM dbo.Equity inner join Instrument on Instrument.InstrumentId = Equity.InstrumentId
UNION
SELECT Instrument.instrumentId, Name, 'Bond' as instrumentType from dbo.Bond inner join Instrument on Instrument.InstrumentId = Bond.InstrumentId) u

one option is to include the table name in your joins like this
SELECT i.InstrumentId,
i.Name,
e.TableEquity,
b.TableBond
FROM Instrument i
LEFT OUTER JOIN (select 'Equity' as TableEquity from Equity) e
ON i.InstrumentId = e.InstrumentId
LEFT OUTER JOIN (select 'Bond' as TableBond from Bond) b
ON i.InstrumentId = b.InstrumentId
EDIT by #sofsntp : to merge the Equity/Bond in one column
SELECT i.InstrumentId,
i.Name,
(ISNULL(e.TableEquity,'') + ISNULL(b.TableBond ,''))
FROM Instrument i
LEFT OUTER JOIN (select *, 'Equity' as TableEquity from Equity) e
ON e.InstrumentId = i.InstrumentId
LEFT OUTER JOIN (select *, 'Bond' as TableBond from StraightBond) b
ON b.InstrumentId = i.InstrumentId

Use a case expression:
SELECT i.InstrumentId, i.Name,
(CASE WHEN e.InstrumentId IS NOT NULL THEN 'Equity'
WHEN b.InstrumentId IS NOT NULL THEN 'Bond'
END) as which_table
FROM Instrument i LEFT OUTER JOIN
Equity e
ON e.InstrumentId = i.InstrumentId LEFT OUTER JOIN
Bond b
ON b.InstrumentId = i.InstrumentId ;
Note: This gives the first match. If you want both:
SELECT i.InstrumentId, i.Name,
((CASE WHEN e.InstrumentId IS NOT NULL THEN 'Equity' ELSE '' END) +
(CASE WHEN b.InstrumentId IS NOT NULL THEN 'Bond' ELSE '' END)
) as which_table
FROM Instrument i LEFT OUTER JOIN
Equity e
ON e.InstrumentId = i.InstrumentId LEFT OUTER JOIN
Bond b
ON b.InstrumentId = i.InstrumentId ;
EDIT
I am adding END which was missing

Related

Retrieving available titles in full outer join of 4 tables

I need to consolidate the output of 4 different attribute tables. All tables have different row count. Currently I have this query:
CREATE VIEW vw_Items
AS
SELECT a.Countryname
,a.Itemname
,ISNULL(a.Colour,'None') as Colour
,ISNULL(b.Location,0) as Location
,ISNULL(c.Size,0) as Size
,ISNULL(d.Weight,0) as Weight
FROM ItemColour a
FULL OUTER JOIN ItemLocation b
ON a.Countryname = b.Countryname
AND a.Itemname= b.Itemname
FULL OUTER JOIN ItemSize c
ON a.Countryname = c.Countryname
AND a.Itemname= c.Itemname
FULL OUTER JOIN ItemWeight d
ON a.Countryname = d.Countryname
AND a.Itemname= d.Itemname
So, the issue is with NULL countryname and Itemname in table a, for which I think I need to do a nested CASE, but is there a better way to handle this?
Thank you.
I suspect you might want:
SELECT ci.Countryname, ci.Itemname
COALESCE(c.Colour, 'None') as Colour,
COALESCE(l.Location, 0) as Location
COALESCE(s.Size, 0) as Size
COALESCE(w.Weight, 0) as Weight
FROM ((SELECT c.countryname, c.itemname
FROM ItemColour c
) UNION -- on purpose to remove duplicates
(SELECT l.countryname, l.itemname
FROM ItemLocation c
) UNION
(SELECT s.countryname, s.itemname
FROM ItemSize
) UNION
(SELECT w.countryname, w.itemname
FROM ItemWeight w
)
) ci LEFT JOIN
ItemColor c
ON c.countryname = ci.countryname AND
c.itemname = ci.itemname LEFT JOIN
ItemLocation l
ON l.countryname = ci.countryname AND
l.itemname = ci.itemname LEFT JOIN
ItemSize s
ON s.countryname = ci.countryname AND
s.itemname = ci.itemname LEFT JOIN
ItemWeight w
ON w.countryname = ci.countryname AND
w.itemname = ci.itemname ;

Count function in a case statement

I have the following query that counts members:
`SELECT
distinct count(cst_recno) AS [Member ID],
adr_country AS Country
FROM
mb_membership
JOIN mb_member_type on mbt_key = mbr_mbt_key
JOIN co_customer ON cst_key=mbr_cst_key and mbr_delete_flag =0 and
cst_delete_flag=0
LEFT JOIN co_individual ON cst_key=ind_cst_key and ind_delete_flag=0
LEFT JOIN co_customer_x_customer ON cxc_cst_key_1 = co_customer.cst_key and
(cxc_end_date is null or datediff(dd,getdate(),cxc_end_date) >=0) and
cxc_rlt_code='Chapter Member'
LEFT JOIN co_chapter ON cxc_cst_key_2=chp_cst_key
LEFT JOIN co_customer_x_address ON cst_cxa_key=cxa_key
LEFT JOIN co_address ON adr_key=cxa_adr_key
LEFT JOIN co_country on adr_country=cty_code
LEFT JOIN co_region on rgn_key=cty_rgn_key
LEFT JOIN vw_client_uli_member_type WITH (NOLOCK) ON cst_key=mem_cst_key
WHERE mbr_join_date >= '7/1/2015' and mbt_code not like '%Council%'
AND ind_int_code <> 'staff' and cst_org_name_dn not like '%urban land ins%'
and cst_eml_address_dn not like '%#uli.org'
and adr_country ='singapore'
group by adr_country`
and the query returns:
Member ID Country
145 Singapore
However, I know that it includes a few duplicates because when I take out a count function and don't have a group by clause it returns 140 distinct rows.
When I check why it includes a few dupes it is caused by one of the dates.
Can you advise? I basically want to run the query that will display 140 distinct count of Member ID:
Member ID Country
140 Singapore
Instead of SELECT distinct count(cst_recno)... use SELECT count(distinct cst_recno)...:
SELECT
count(distinct cst_recno) AS [Member ID],
adr_country AS Country
FROM
mb_membership
JOIN mb_member_type on mbt_key = mbr_mbt_key
JOIN co_customer ON cst_key=mbr_cst_key and mbr_delete_flag =0 and
cst_delete_flag=0
LEFT JOIN co_individual ON cst_key=ind_cst_key and ind_delete_flag=0
LEFT JOIN co_customer_x_customer ON cxc_cst_key_1 = co_customer.cst_key and
(cxc_end_date is null or datediff(dd,getdate(),cxc_end_date) >=0) and
cxc_rlt_code='Chapter Member'
LEFT JOIN co_chapter ON cxc_cst_key_2=chp_cst_key
LEFT JOIN co_customer_x_address ON cst_cxa_key=cxa_key
LEFT JOIN co_address ON adr_key=cxa_adr_key
LEFT JOIN co_country on adr_country=cty_code
LEFT JOIN co_region on rgn_key=cty_rgn_key
LEFT JOIN vw_client_uli_member_type WITH (NOLOCK) ON cst_key=mem_cst_key
WHERE mbr_join_date >= '7/1/2015' and mbt_code not like '%Council%'
AND ind_int_code <> 'staff' and cst_org_name_dn not like '%urban land ins%'
and cst_eml_address_dn not like '%#uli.org'
and adr_country ='singapore'
group by adr_country`

SQL SUM columns from different tables

Good Afternoon,
I currently have the query:
SELECT erp_user.login,
SUM(invoice_header.invoice_amount) as 'Invoices Billed'
FROM erp_user
LEFT JOIN order_header ON erp_user.erp_user_id = order_header.req_by
LEFT JOIN invoice_instruct_header ON order_header.order_id = invoice_instruct_header.order_id
LEFT JOIN invoice_header ON invoice_instruct_header.instruct_id = invoice_header.instruct_no
WHERE erp_user.supervisor_id IS NOT NULL AND user_id_type = 'I' AND erp_user.company_id IS NOT NULL AND erp_user.is_active = 1
GROUP BY erp_user.login
It gives me a list of total billing in our system by employee where the employee is signed to a job on the job header.
I would love to add the total amount of open PO's to this query so I added:
SELECT erp_user.login, SUM(invoice_header.invoice_amount) as 'Invoices Billed', sum(po_header.po_amount) AS "Open PO's"
FROM erp_user
LEFT JOIN order_header ON erp_user.erp_user_id = order_header.req_by
LEFT JOIN invoice_instruct_header ON order_header.order_id = invoice_instruct_header.order_id
LEFT JOIN invoice_header ON invoice_instruct_header.instruct_id = invoice_header.instruct_no
LEFT JOIN po_header ON order_header.order_id = po_header.order_id
WHERE erp_user.supervisor_id IS NOT NULL AND user_id_type = 'I' AND erp_user.company_id IS NOT NULL AND erp_user.is_active = 1 AND po_header.status = 1
GROUP BY erp_user.login
ORDER BY "Open PO's"
That query gives me numbers in my Open PO's column, but they are incorrect and I'm at the point now where I can't figure out how to troubleshoot this.
Can someone please point me in the right direction? I don't mind doing the work, just need a pointer. Thanks!
Please be aware of conbination of Left join and Where clause.
SELECT erp_user.login
, SUM(invoice_header.invoice_amount) as 'Invoices Billed'
, sum(CASE WHEN po_header.status = 1 THEN po_header.po_amount ELSE 0 END) AS "Open PO's"
FROM erp_user
LEFT JOIN order_header ON erp_user.erp_user_id = order_header.req_by
LEFT JOIN invoice_instruct_header ON order_header.order_id = invoice_instruct_header.order_id
LEFT JOIN invoice_header ON invoice_instruct_header.instruct_id = invoice_header.instruct_no
LEFT JOIN po_header ON order_header.order_id = po_header.order_id
WHERE erp_user.supervisor_id IS NOT NULL
AND user_id_type = 'I'
AND erp_user.company_id IS NOT NULL
AND erp_user.is_active = 1
GROUP BY erp_user.login
ORDER BY "Open PO's";
If po_header joins to order_header, then in your original query it would be repeating each po_header for each invoice_header as well (leading to the incorrect calculation).
You could use outer apply() like so:
select
erp_user.login
, [Invoices Billed] = sum(invoice_header.invoice_amount)
, x.[Open POs]
from erp_user
left join order_header
on erp_user.erp_user_id = order_header.req_by
left join invoice_instruct_header
on order_header.order_id = invoice_instruct_header.order_id
left join invoice_header
on invoice_instruct_header.instruct_id = invoice_header.instruct_no
outer apply (
select
[Open POs] = sum(po_header.po_amount)
from po_header p
inner join order_header oh
on oh.order_id = p.order_id
where oh.req_by = erp_user.erp_user_id
) x
where erp_user.supervisor_id is not null
and erp_user.company_id is not null
and erp_user.is_active = 1
and user_id_type = 'I'
group by erp_user.login

Select qry to using 2 databases

I have the below query:
SELECT
--a.DateEntered,
--a.InventoryId,
a.SKU, a.QtyOnHand,
b.Dateentered AS VDateEntered,
b.GoLive, b.DateOnSite, b.CostPrice,
--a.CurrentPrice,
m.name AS Status,
hrf.category, hrf.department, hrf.BrandedOB, hrf.Division,
hrf.Fascia,
(a.QtyOnHand * b.CostPrice) AS Cost_Value,
NULL AS Item_Quantity, NULL AS Item,
NULL AS Season, hrf.Company,
(a.QtyOnHand * b.CurrentPrice) AS Sellilng_Value,
b.merchandisingseason, b.CostPrice AS Costprice_RP,
b.CurrentPrice, b.InventoryID,
-- a.AverageUnitCost,
-- a.AverageUnitCost AS RP_Stk_AverageUnitCost,
-- a.CurrentPrice AS RP_Stk_Current_Price,
-- a.Statusid,
-- a.Quantity_Sign,
(a.QtyOnHand * b.CostPrice) AS Cost_Value_RP,
(a.QtyOnHand * b.AverageUnitCost) AS AWC_Value
-- a.StockReconciliationId,
-- a.AverageUnitCost,
FROM
[dbo].[FC03QTY] a
JOIN
dbo.inventory b ON a.SKU = b.SKU
LEFT JOIN
(------Hierarchy-------
SELECT
ih.InventoryId, hry.category, hry.department,
hry.BrandedOB, hry.Division, hry.Fascia, hry.Company
FROM
(SELECT
ihn.HierarchyNodeId, ihn.InventoryId
FROM bm.InventoryHierarchyNode IHN
GROUP BY ihn.HierarchyNodeId, ihn.InventoryId) IH
JOIN
(SELECT
g.categoryid, g.category, h.department, i.BrandedOB,
j.Division, K.Fascia, L.company
FROM
Category g (NOLOCK)
JOIN
Department H ON g.departmentid = h.departmentID
JOIN
BrandedOB I (NOLOCK) ON h.BrandedOBID = i.BrandedOBID
JOIN
Division j (NOLOCK) ON i.divisionid = j.divisionid
JOIN
Fascia k (NOLOCK) ON j.fasciaid = k.fasciaID
JOIN
company l (NOLOCK) ON k.companyid = l.companyid
GROUP BY
g.categoryid, g.category, h.department,
i.BrandedOB, j.Division, K.Fascia, L.company) HRY ON ih.HierarchyNodeId = hry.CategoryId
GROUP BY
ih.InventoryId, hry.category, hry.department,
hry.BrandedOB, hry.Division, hry.Fascia, hry.Company) HRF ON b.inventoryid = hrf.inventoryid
JOIN
inventorystatus m (NOLOCK) ON b.statusid = m.statusid
It is using 2 tables -
[dbo].[FC03QTY] a
and
dbo.inventory b
that are joined at the SKU level.
[dbo].[FC03QTY] is on the scratch database and dbo.inventory is on the reports database.
How can I get my query to use these tables if they are on 2 different db?
Any advice greatly received.
In sql server the syntaxis for tables is [database name].[schema name].[table name]
So you need something like this:
SELECT A.*, B.*
FROM
Database1.dbo.Table1 as A,
Database2.dbo.Table2 as B

Problems with Sql query join

I am struggling with a sql query. I want to include the sum from an other table.
SELECT DISTINCT
tblProject.CompanyID,
tblCompany.Name,
tblCompany.AvtalsKund,
tblProject.ProjectName,
tblProject.Estimate,
tblProject.ProjectStart,
tblProject.Deadline,
CONVERT(VARCHAR(8), tblProject.Deadline, 2) AS [YY.MM.DD] ,
tblProject.PreOffered,
tblProject.ProjectType,
tblProjectType.ProjType,
tblOrdered.FirstName + + tblOrdered.LastName as OrderedFullName,
tblProject.ProjectID,
tblProject.RegDate,
tblProject.ProjectNr,
tblProject.ProjectNr
FROM tblProject
INNER JOIN tblCompany ON tblProject.CompanyID = tblCompany.CompanyID
---> INNER JOIN (SELECT tblTimeRecord.ProjectID, SUM(CONVERT(float,replace([Hours],',','') ))
FROM tblTimeRecord group by tblTimeRecord.ProjectID) as b
ON b.ProjectID = tblProject.ProjectID
INNER JOIN tblTimeRecord ON tblTimeRecord.ProjectID = tblProject.ProjectID
INNER JOIN tblProjectType ON tblProject.ProjectType = tblProjectType.ProjTypeID
LEFT OUTER JOIN tblOrdered ON tblProject.OrderedBy = tblOrdered.OrderedID
LEFT OUTER JOIN tblRel_WorkerProject ON tblProject.ProjectID = tblRel_WorkerProject.ProjectID
LEFT OUTER JOIN tblPerson ON tblPerson.PersonID = tblRel_WorkerProject.WorkerID
LEFT OUTER JOIN tblRel_StatusWorkerProject ON tblProject.ProjectID = tblRel_StatusWorkerProject.ProjectID
I want to include this sum-block from table tblTimeRecord.
I get a sum of timerapports with this code
SELECT tblTimeRecord.ProjectID,
SUM(CONVERT(float,replace([Hours],',','') ))
FROM tblTimeRecord where ProjectID=1312 group by tblTimeRecord.ProjectID
Guess i do it in join?
Got it working with this.
SELECT DISTINCT
tblProject.ProjectID,
Summa,
tblProject.CompanyID,
tblCompany.Name,
tblCompany.AvtalsKund,
tblProject.ProjectName,
tblProject.Estimate,
tblProject.ProjectStart,
tblProject.Deadline,
CONVERT(VARCHAR(8), tblProject.Deadline, 2) AS [YY.MM.DD] ,
tblProject.PreOffered,
tblProject.ProjectType,
tblProjectType.ProjType,
tblOrdered.FirstName + + tblOrdered.LastName as OrderedFullName,
tblProject.ProjectID,
tblProject.RegDate,
tblProject.ProjectNr,
tblProject.ProjectNr
FROM tblProject
INNER JOIN tblCompany ON tblProject.CompanyID = tblCompany.CompanyID
INNER JOIN (SELECT tblTimeRecord.ProjectID, SUM(CONVERT(float,replace([Hours],',','') )) as Summa FROM tblTimeRecord group by tblTimeRecord.ProjectID) as b
ON b.ProjectID = tblProject.ProjectID
INNER JOIN tblTimeRecord ON tblTimeRecord.ProjectID = tblProject.ProjectID
INNER JOIN tblProjectType ON tblProject.ProjectType = tblProjectType.ProjTypeID
LEFT OUTER JOIN tblOrdered ON tblProject.OrderedBy = tblOrdered.OrderedID
LEFT OUTER JOIN tblRel_WorkerProject ON tblProject.ProjectID = tblRel_WorkerProject.ProjectID
LEFT OUTER JOIN tblPerson ON tblPerson.PersonID = tblRel_WorkerProject.WorkerID
LEFT OUTER JOIN tblRel_StatusWorkerProject ON tblProject.ProjectID = tblRel_StatusWorkerProject.ProjectID
There are two ways to do this.
You can use a WITH clause to create the aggregate table then join this to the main query.
Or do it this way:
SELECT m.BLAH
,m.FOO
,x.AMOUNT
FROM MAINTABLE m
LEFT JOIN
(
SELECT FOO
,SUM(AMOUNT) as AMOUNT
FROM OTHERTABLE
GROUP BY FOO
) x
ON m.FOO = x.FOO
I prefer the second way.