Here is my SQL
SELECT DISTINCT
AID.INVOICE_ID,
AID.AMOUNT,
AID.PERIOD_NAME,
GCC.SEGMENT1 as Organisation,
GCC.SEGMENT2,
GCC.SEGMENT3,
GCC.SEGMENT4,
INV.INVOICE_NUM,
INV.CREATION_DATE,
PO.SEGMENT1 as PO_Number,
SUP.VENDOR_NAME,
AID.LINE_TYPE_LOOKUP_CODE,
LINES.LINE_NUMBER
FROM
AP_INVOICES_All INV
INNER JOIN
AP_INVOICE_LINES_ALL LINES
ON INV.INVOICE_ID = LINES.INVOICE_ID
INNER JOIN
AP_INVOICE_DISTRIBUTIONS_ALL AID
ON INV.INVOICE_ID = AID.INVOICE_ID
INNER JOIN
GL_CODE_COMBINATIONS GCC
ON AID.DIST_CODE_COMBINATION_ID = GCC.CODE_COMBINATION_ID
INNER JOIN
POZ_SUPPLIERS_V SUP
ON INV.VENDOR_ID = SUP.VENDOR_ID
LEFT JOIN
PO_HEADERS_ALL PO
ON LINES.PO_HEADER_ID = PO.PO_HEADER_ID
LEFT JOIN
PO_DISTRIBUTIONS_ALL PDA
ON INV.INVOICE_ID = PDA.PO_DISTRIBUTIONS_ALL
WHERE
AID.LINE_TYPE_LOOKUP_CODE NOT IN
(
'REC_TAX',
'NONREC_TAX'
)
AND LINES.LINE_TYPE_LOOKUP_CODE NOT IN
(
'TAX'
)
END
ORDER BY
AID.INVOICE_ID,
LINES.LINE_NUMBER
I am looking at something similar to the below. What I want to say is that if PO.SEGMENT is null, then select the columns from a table using the join specified. Use different columns in the join depending on whether PO.SEGMENT is null or not. Is this easily achievable?
CASE
WHEN PO.SEGMENT IS NOT NULL
THEN SEGMENT1,SEGMENT2,SEGMENT3,SEGMENT4
FROM GCC.CODE_COMBINATION_ID
WHERE PDA.CODE_COMBINATION_ID = GCC.CODE_COMBINATION_ID
WHEN PO.SEGMENT IS NULL
THEN SEGMENT1,SEGMENT2,SEGMENT3,SEGMENT4
FROM GCC.CODE_COMBINATION_ID
WHERE AID.DIST_CODE_COMBINATION_ID = GCC.CODE_COMBINATION_ID
END
How about rephrasing your logic so that you just have a single ON clause:
ON
(PO.SEGMENT IS NOT NULL AND PDA.CODE_COMBINATION_ID = GCC.CODE_COMBINATION_ID) OR
(PO.SEGMENT IS NULL AND AID.DIST_CODE_COMBINATION_ID = GCC.CODE_COMBINATION_ID)
I left out the other details of the rest of your query, but I suggest this because it may be possible to achieve what you want with careful logic.
Related
I'm trying to write a custom report whereby the invoices will either have a PO number in the PO_Number Column or they wont.
If they don't have a PO number I'm looking to get data from 4 Columns (Segment1, Segment2, Segment3 and Segment4) where 2 ID numbers are the same. In the same statement in the event that there is a PO number I want to pull the same 4 columns but where 2 different ID numbers match.
The SQL I have so far is:
SELECT DISTINCT
AID.INVOICE_ID,
AID.AMOUNT,
AID.PERIOD_NAME,
GCC.SEGMENT1 as Organisation,
GCC.SEGMENT2,
GCC.SEGMENT3,
GCC.SEGMENT4,
INV.INVOICE_NUM,
INV.CREATION_DATE,
PO.SEGMENT1 as PO_Number,
SUP.VENDOR_NAME,
AID.LINE_TYPE_LOOKUP_CODE,
LINES.LINE_NUMBER
FROM
AP_INVOICES_All INV
INNER JOIN
AP_INVOICE_LINES_ALL LINES
ON INV.INVOICE_ID = LINES.INVOICE_ID
INNER JOIN
AP_INVOICE_DISTRIBUTIONS_ALL AID
ON INV.INVOICE_ID = AID.INVOICE_ID
INNER JOIN
GL_CODE_COMBINATIONS GCC
ON AID.DIST_CODE_COMBINATION_ID = GCC.CODE_COMBINATION_ID
INNER JOIN
POZ_SUPPLIERS_V SUP
ON INV.VENDOR_ID = SUP.VENDOR_ID
LEFT JOIN
PO_HEADERS_ALL PO
ON LINES.PO_HEADER_ID = PO.PO_HEADER_ID
WHERE
AID.LINE_TYPE_LOOKUP_CODE NOT IN
(
'REC_TAX',
'NONREC_TAX'
)
AND LINES.LINE_TYPE_LOOKUP_CODE NOT IN
(
'TAX'
)
ORDER BY
AID.INVOICE_ID,
LINES.LINE_NUMBER
If there is a PO I want the match to be done on:
PO_DISTRIBUTIONS_ALL.CODE_COMBINATION_ID = GCC.CODE_COMBINATION_ID
And if there isn't a PO:
AID.DIST_CODE_COMBINATION_ID = GCC.CODE_COMBINATION_ID
(I know I need to reference the PO_DISTRIBUTIONS_ALL table somewhere but not sure where)
Any help would be great as I'm pretty new to SQL and don't know how to express what I want to achieve in SQL code.
Let me know if I haven't been clear on any parts
You can left join PO_DISTRIBUTION_ALL and create conditional join on GL_CODE_COMBINATIONS like this:
SELECT DISTINCT
AID.INVOICE_ID,
AID.AMOUNT,
AID.PERIOD_NAME,
GCC.SEGMENT1 as Organisation,
GCC.SEGMENT2,
GCC.SEGMENT3,
GCC.SEGMENT4,
INV.INVOICE_NUM,
INV.CREATION_DATE,
PO.SEGMENT1 as PO_Number,
SUP.VENDOR_NAME,
AID.LINE_TYPE_LOOKUP_CODE,
LINES.LINE_NUMBER
FROM AP_INVOICES_All INV
INNER JOIN AP_INVOICE_LINES_ALL LINES
ON INV.INVOICE_ID = LINES.INVOICE_ID
INNER JOIN AP_INVOICE_DISTRIBUTIONS_ALL AID
ON INV.INVOICE_ID = AID.INVOICE_ID
LEFT JOIN PO_HEADERS_ALL PO
ON LINES.PO_HEADER_ID = PO.PO_HEADER_ID
LEFT JOIN PO_DISTRIBUTIONS_ALL PDA
ON PO.PO_HEADER_ID = PDA.PO_HEADER_ID
INNER JOIN GL_CODE_COMBINATIONS GCC
ON GCC.CODE_COMBINATION_ID = nvl(PDA.CODE_COMBINATION_ID, AID.DIST_CODE_COMBINATION_ID)
INNER JOIN
POZ_SUPPLIERS_V SUP
ON INV.VENDOR_ID = SUP.VENDOR_ID
WHERE AID.LINE_TYPE_LOOKUP_CODE NOT IN ( 'REC_TAX', 'NONREC_TAX')
AND LINES.LINE_TYPE_LOOKUP_CODE NOT IN ('TAX')
ORDER BY
AID.INVOICE_ID,
LINES.LINE_NUMBER
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
I have this query:
Select b.building_pk, bil.building_fk, bil.BillingAccountStatus_fk, b.ACTL_TNT_CT
From [DB].[Schema].Building b (nolock)
left Join [DB].[Schema].Billing bil (nolock) on bil.building_fk = b.building_pk
join ##GlobalTempTable1 tt (nolock) on tt.Building_fk = b.building_pk
Order by b.building_pk;
It works fine. But I want to override NULLs in the result set in columns bil.building_fk and bil.BillingAccountStatus_fk as not everything in Billing tbl exists in building table.
So wrote the following query below, but getting this error message.
Msg 102, Level 15, State 1, Line 7 Incorrect syntax near '='.
Please assist.
SELECT b.building_pk, bil.building_fk As [BLD Key from Billing], bil.BillingAccountStatus_fk, b.ACTL_TNT_CT As [ActualTenantCount]
FROM [DB].[Schema].Building b (nolock)
join ##GlobalTempTable1 tt (nolock) ON tt.Building_fk = b.building_pk
left Join [DB].[Schema].Billing bil (nolock) ON
CASE
WHEN bil.building_fk IS NOT NULL
THEN bil.building_fk = b.building_pk AND bil.BillingAccountStatus_fk = bil.BillingAccountStatus_fk
WHEN bil.building_fk IS NULL
THEN bil.building_fk = NULL AND bil.BillingAccountStatus_fk = 'Not in Billing'
END
ORDER BY b.building_pk;
It's hard to tell what you are trying to do because it's very wrong. I think, though, that you want to keep your FROM the same and do the CASE statement up into the SELECT.
Select b.building_pk, CASE WHEN bil.Building_fk IS NULL THEN 'Not in Billing' ELSE bil.building_fk END as building_fk, bil.BillingAccountStatus_fk, b.ACTL_TNT_CT
From [DB].[Schema].Building b (nolock)
left Join [DB].[Schema].Billing bil (nolock) on bil.building_fk = b.building_pk
join ##GlobalTempTable1 tt (nolock) on tt.Building_fk = b.building_pk
Order by b.building_pk;
Or, better yet, use COALESCE() here:
Select b.building_pk, COALESCE(bil.Building_fk,'Not in Billing') as building_fk, bil.BillingAccountStatus_fk, b.ACTL_TNT_CT
From [DB].[Schema].Building b (nolock)
left Join [DB].[Schema].Billing bil (nolock) on bil.building_fk = b.building_pk
join ##GlobalTempTable1 tt (nolock) on tt.Building_fk = b.building_pk
Order by b.building_pk;
I am guessing that you are trying to do something like this:
SELECT b.building_pk, bil.building_fk As [BLD Key from Billing], bil.BillingAccountStatus_fk, b.ACTL_TNT_CT As [ActualTenantCount]
FROM [DB].[Schema].Building b (nolock)
join ##GlobalTempTable1 tt (nolock) ON tt.Building_fk = b.building_pk
left Join [DB].[Schema].Billing bil (nolock) ON
(bil.building_fk IS NOT NULL AND
(bil.building_fk = b.building_pk AND bil.BillingAccountStatus_fk = bil.BillingAccountStatus_fk))
OR (bil.building_fk IS NULL AND
(bil.building_fk = NULL AND bil.BillingAccountStatus_fk = 'Not in Billing'))
ORDER BY b.building_pk;
I'll leave the misguided use of nolock for another day ...
CASE expressions can't be used to set which criteria you use for a JOIN, they can be used on either side of the comparison operator in JOIN criteria, but I don't think you need that, I think you just need a LEFT JOIN and a COALESCE() in your SELECT:
SELECT b.building_pk
, bil.building_fk As [BLD Key from Billing]
, COALESCE(bil.BillingAccountStatus_fk,'Not in Billing')
, b.ACTL_TNT_CT As [ActualTenantCount]
FROM [DB].[Schema].Building b
join ##GlobalTempTable1 tt
ON tt.Building_fk = b.building_pk
left Join [DB].[Schema].Billing bil
ON bil.building_fk = b.building_pk
ORDER BY b.building_pk;
Edit: Noticed BillingAccountStatus_fk was coming from bil on both sides, so removed that from the JOIN criteria.
is there any way that i can restructure this below query without using intersect. Because using intersect causing very slow performance. Please suggest
SELECT DISTINCT( PFM.id ) AS PfmFolderFK
FROM cm.pfmfolder PFM WITH(nolock)
INNER JOIN cm.pfmfoldermstipmap PFMMST WITH(nolock)
ON PFMMST.pfmfolderfk = PFM.id
INNER JOIN cm.mstip MST WITH(nolock)
ON MST.id = PFMMST.mstipfk
WHERE MST.registrycode = #RegistryCode
AND PFM.deletedby IS NULL
AND PFM.deleteddate IS NULL
INTERSECT
SELECT DISTINCT( FMAP.pfmfolderfk ) AS PfmFolderFK
FROM cm.mstip MIP WITH(nolock)
INNER JOIN cm.pfmfoldermstipmap FMAP WITH(nolock)
ON MIP.id = FMAP.mstipfk
AND MIP.registrycode = #RegistryCode
AND MIP.deletedby IS NULL
AND MIP.deletedate IS NULL
An intersect is taking values from both tables. The queries are quite similar here, so I think you just need an additional join in the first table to complete the logic without an intersect:
SELECT DISTINCT( PFM.id ) AS PfmFolderFK
FROM cm.pfmfolder PFM WITH(nolock) INNER JOIN
cm.pfmfoldermstipmap PFMMST WITH(nolock)
ON PFMMST.pfmfolderfk = PFM.id INNER JOIN
cm.mstip MST WITH(nolock)
ON MST.id = PFMMST.mstipfk INNER JOIN
cm.pfmfoldermstipmap FMAP WITH(nolock)
ON PFMMST.id = FMAP.mstipfk AND
PFMMST.registrycode = #RegistryCode AND
PFMMST.deletedby IS NULL AND
PFMMST.deletedate IS NULL
WHERE MST.registrycode = #RegistryCode AND
PFM.deletedby IS NULL AND
PFM.deleteddate IS NULL;
How about this? I think you need to take only the first part of your query and add two contitions to it.
SELECT DISTINCT FMAP.pfmfolderfk AS PfmFolderFK
FROM cm.mstip MST WITH(nolock)
INNER JOIN cm.pfmfoldermstipmap FMAP WITH(nolock) ON MST.id = FMAP.mstipfk
INNER JOIN cm.pfmfolder PFM WITH(nolock) ON FMAP.pfmfolderfk = PFM.id
WHERE MST.registrycode = #RegistryCode
AND PFM.deletedby IS NULL
AND PFM.deleteddate IS NULL
AND MST.deletedby IS NULL
AND MST.deletedate IS NULL
Queries with DISTINCT are always dubious ;-) You are looking for pfmfolders where certain records exist in pfmfoldermstipmap and mstip. Use EXISTS for that. Actually you are looking for all pfmfolders that are in pfmfoldermstipmap and mstip and are either not deleted themselves or having not deleted mstips:
select id
from cm.pfmfolder
where exists
(
select *
from cm.pfmfoldermstipmap
inner join cm.mstip on mstip.id = pfmfoldermstipmap.mstipfk
and pfmfoldermstipmap.pfmfolderfk = pfmfolder.id
and mstip.registrycode = #registrycode
and
(
(pfmfolder.deletedby is null and pfmfolder.deleteddate is null)
or
(mstip.deletedby is null and mstip.deleteddate is null)
)
);
I have the following query:
SELECT rt.ID, rt.Name, rt.Rate, rt.Colour, vtb.ID AS 'vtbID', vtb.Value, rt.StdID
FROM Rates AS rt
LEFT OUTER JOIN VehicleTypeCostsBreakdown AS vtb ON rt.ID = vtb.RateID
LEFT OUTER JOIN VehicleTypeCostsDepots AS vtd ON vtd.ID = vtb.VehicleTypeDepotID AND vtd.DepotID = #DepotID AND vtd.VehicleTypeID = #VehicleTypeID
Basically, I want to select all 'rates' from Rates table, but if any references to a rate exists in the 'vtd' table, which has parameters that match #DepotID and #VehicleTypeID, I want to bring back the Value for that. If it doesn't have any referenced, I want it the 'vtb.Value' selection to be blank.
With the SQL above, it seems to always return a value for 'vtb.Value' value, even if the parameters are null. Am I missing something?
Try it this way. Basically, you'll LEFT JOIN to the derived table formed by the INNER JOIN between VehicleTypeCostsBreakdown and VehicleTypeCostsDepots. The INNER JOIN will only match when all of your conditions are true.
SELECT rt.ID, rt.Name, rt.Rate, rt.Colour, vtb.ID AS 'vtbID', vtb.Value, rt.StdID
FROM Rates AS rt
LEFT OUTER JOIN VehicleTypeCostsBreakdown AS vtb
INNER JOIN VehicleTypeCostsDepots AS vtd
ON vtd.ID = vtb.VehicleTypeDepotID
AND vtd.DepotID = #DepotID
AND vtd.VehicleTypeID = #VehicleTypeID
ON rt.ID = vtb.RateID
Try:
SELECT rt.ID, rt.Name, rt.Rate, rt.Colour, vtb.ID AS 'vtbID', vtb.Value, rt.StdID
FROM Rates AS rt
LEFT OUTER JOIN (SELECT b.ID, b.Value, b.RateID
FROM VehicleTypeCostsBreakdown AS b
JOIN VehicleTypeCostsDepots AS d
ON d.ID = b.VehicleTypeDepotID AND
d.DepotID = #DepotID AND
d.VehicleTypeID = #VehicleTypeID)
AS vtb ON rt.ID = vtb.RateID
Try this:
SELECT rt.ID, rt.Name, rt.Rate, rt.Colour, vtb.ID AS 'vtbID', vtb.Value, rt.StdID
FROM Rates AS rt
LEFT JOIN VehicleTypeCostsBreakdown AS vtb ON rt.ID = vtb.RateID
LEFT JOIN VehicleTypeCostsDepots AS vtd ON vtd.ID = vtb.VehicleTypeDepotID
WHERE vtd.ID IS NULL OR (vtd.DepotID = #DepotID AND vtd.VehicleTypeID = #VehicleTypeID)
You don't need to specify that the LEFT JOIN is an OUTER JOIN and you shouldn't put conditions in the ON section of a JOIN, that's what WHERE is for.