SQL Joining tables with 'constants' - sql

I have a table of orders,
Invoice Location Customer Code SalesPersonEmail
------------------------------------------------------
300001 001 CUS001 ?
300002 006 CUS002 ?
And a table of email groups,
Role Email
-----------------------------------------------------
Filtered_Group Management#gmail.com;john#gmail.com
When Location = 001, SalesPersonEmail must be the Email field from Filtered_Group
SalesPersonEmail for all other locations must be "Orders#gmail.com;" + the Email for Role No_Filter_Group.
I'm currently using the following to achieve this,
SELECT i.Invoice, i.Location, i.[Customer Code],
CASE WHEN i.Location = 001
THEN f.Email
ELSE N'Orders#gmail.com;' + nf.Email as SalesPersonEmail
END
FROM Invoice i, RoleCodes f, RoleCodes nf
WHERE f.Role = N'Filtered_Group' AND nf.Role = N'No_Filter_Group'
My problem is the Role No_Filter_Group may not exist in the Role table at times, which causes the above query to return nothing.
How do I join these tables properly so if No_Filter_Group does not exist in the table, rows that have a SalesPersonEmail of Filtered_Group are still returned from the query?
Thanks

A relatively simple way is to use LEFT JOIN and put the special number 001 for your location and special role names Filtered_Group and No_Filter_Group in the join condition.
In this SQL Fiddle you can comment/uncomment one line in the schema definition to see how it works when RoleCodes has a row with No_Filter_Group and when it doesn't.
In any case, the query would return all rows from Invoice table.
SELECT
Invoice.Invoice
,Invoice.Location
,Invoice.[Customer Code]
,CASE WHEN Invoice.Location = '001'
THEN RoleCodes.Email
ELSE 'Orders#gmail.com;' + ISNULL(RoleCodes.Email, '')
END AS SalesPersonEmail
FROM
Invoice
LEFT JOIN RoleCodes ON
(Invoice.Location = '001'
AND RoleCodes.Role = 'Filtered_Group')
OR
(Invoice.Location <> '001'
AND RoleCodes.Role = 'No_Filter_Group')

Try something like this.
Note: This is just a example am not sure about the tables and column of your schema. Replace with the respective tables and columns
SELECT CASE
WHEN location = '001' THEN (SELECT TOP 1 email
FROM email_table
WHERE [role] = 'Filtered_Group')
ELSE 'Orders#gmail.com;'
END
FROM orders
If email_table table will have only one row for [role] = 'Filtered_Group' then you can remove the TOP 1 from the sub-query

Left join or an easier, albeit less efficient method would be to do a subquery in the select statement itself.
SELECT i.Invoice, i.Location, i.[Customer Code],
CASE WHEN i.Location = 001
THEN (SELECT TOP 1 f.Email FROM RoleCodes f WHERE f.Role = N'Filtered_Group')
ELSE N'Orders#gmail.com;' + ISNULL( (SELECT nf.Email as SalesPersonEmail FROM RoleCodes nf WHERE nf.Role = N'No_Filter_Group'), '')
END
FROM Invoice i
Normally you would want to join these in on each other but I'm not certain how you would do that with the schema provided.

Nested select will be run for each row, instead, you could try this :-
Select i.Invoice
,i.Location
,i.CustomerCode
,Isnull(r.Email,'Orders#gmail.com') As SalesPersonEmail
From Invoice As i With (Nolock)
Left Join
(
Select rc.Email
,'001' As Location
From RoleCodes As rc With (Nolock)
Where rc.Role = 'Filtered_Group'
) As r On i.Location = r.Location

use the following Query:
select t.Invoice,t.Location,t.[Customer Code],
case t.Location
when '001' then
t2.Email
else
'Orders#gmail.com'
end
as
Salespersonemail
from orders t
join email_groups t2 on t2.Role='Filtered_Group'

Related

Subquery returned more than 1 value - MS SQL

select Id,Prayaseeid, name,Gender,
(select name from tb_Category where id = Category) AS Category,
ideadescription,Domain,ProjectTerms,ProjectStartDate,Amountsanctioned,
(select Amount from tb_innovatorDisbursement where tbid ='TBINO1111A' and
applyingforcycle='1') AS AmountDisbursed,
projectstatus,projectoutcome
from tb_innovator
where tbid='TBINO1111A 'and applyingforcycle='1'
Use TOP to Limit rows to 1,
The Select queries in parenthesis resulting in more than one record
select Id,Prayaseeid, name,Gender,
(select TOP(1) name from tb_Category where id = Category) AS Category,
ideadescription,Domain,ProjectTerms,ProjectStartDate,Amountsanctioned,
(select TOP(1) Amount
from tb_innovatorDisbursement where tbid ='TBINO1111A' and applyingforcycle='1') AS AmountDisbursed,
projectstatus,projectoutcome from tb_innovator
where tbid='TBINO1111A 'and applyingforcycle='1'
You need to test your sub queries for the where clause to make sure the values you are searching do not have multiple records. I would use (Top 1 ) for any column other than the Id column assuming the Id column must be unique as the name suggests.
Update query
select ti.Id,
ti.Prayaseeid,
ti.name,
ti.Gender,
(select TOP(1) name from tb_Category where id = ti.Category) AS Category,
ti.ideadescription,
ti.Domain,
ti.ProjectTerms,
ti.ProjectStartDate,
ti.Amountsanctioned,
tid.Amount AS AmountDisbursed,
ti.projectstatus,
ti.projectoutcome
from tb_innovator ti
INNER JOIN tb_innovatorDisbursement tid ON tid.Tbid = ti.tbid
AND tid.applyingforcycle='1'
where ti.tbid='TBINO1111A 'and ti.applyingforcycle='1'
Perhaps you should use JOIN:
select i.Id, i.Prayaseeid, i.name, i.Gender, c.Category,
i.ideadescription, i.Domain, i.ProjectTerms, i.ProjectStartDate, i.Amountsanctioned,
id.Amount from tb_innovatorDisbursement
i.projectstatus, i.projectoutcome
from tb_innovator i left join
tb_Category c
on i.category = c.id left join
tb_innovatorDisbursement id
on id.tbid = i.dbid and id.applyingforcycle = '1'
where i.tbid = 'TBINO1111A 'and i.applyingforcycle = '1';
Note that all column names are qualified as well, indicating what table they come from.

SQL (server 2016) - Using the result of a CASE as where-clause of a sub-query

I'm using SQL Server 2016. I have a select-statement with a CASE. This CASE gives back a country-code. In the same select-statement I would like to query another table to retrieve the description which goes with this country-code. In order to do so I have created a subquery. In this subquery I want to use the result of the case in the where-clause.
SELECT
DelAddrCode
, CASE WHEN DelAddrCode = '0' THEN (SELECT Customeraddress.countrycode FROM Customeraddress WHERE Customeraddress.CustID = Salesorder.CustID)
ELSE (SELECT Deliveryaddress.countrycode FROM Deliveryaddress where Deliveryaddress.CustID = Salesorder.CustID AND Deliveryaddress.DelAddrCode = Salesorder.DelAddrCode)
END AS delivery_country
, (SELECT country.description from Country WHERE Country.countrycode = delivery_country)
FROM Salesorder
The logic here is that you have a default customer address, for instance in the US, but you can deliver a sales order on a different address like the UK. So first I retrieve the DelAddrCode. If 0 then I retrieve the countrycode from the CustomerAdress table. If not 0, then I will get the countrycode from the Deliveryaddress table.
Now that I have the countrycode I would like to get the country description from the Country table. I use a subquery for this. But the where-clause of this subquery depends on the result of the CASE. The above query gives an error: "Invalid column name 'del_country'".
The solution I found is to copy past the case and put it in the subquery:
SELECT
DelAddrCode
, CASE WHEN DelAddrCode = '0' THEN (SELECT Customeraddress.countrycode FROM Customeraddress WHERE Customeraddress.CustID = Salesorder.CustID)
ELSE (SELECT Deliveryaddress.countrycode FROM Deliveryaddress where Deliveryaddress.CustID = Salesorder.CustID AND Deliveryaddress.DelAddrCode = Salesorder.DelAddrCode)
END AS delivery_country
, (SELECT country.description from Country WHERE Country.countrycode =
(CASE WHEN DelAddrCode = '0' THEN (SELECT Customeraddress.countrycode FROM Customeraddress WHERE Customeraddress.CustID = Salesorder.CustID)
ELSE (SELECT Deliveryaddress.countrycode FROM Deliveryaddress WHERE Deliveryaddress.CustID = Salesorder.CustID and Deliveryaddress.DelAddrCode = Salesorder.DelAddrCode)
END))
FROM Salesorder
This gives me the result I want, but it makes the code a mess. Is there a way I can refer to the result of the CASE in the subquery to get the same result without having to copy-paste the same CASE again?
Thanks in advance!
Try the following code. It contains the CASE just once and I find it more readable.
SELECT t.delAddrCode,
country.description
FROM
(
SELECT Salesorder.DelAddrCode,
CASE
WHEN Salesorder.DelAddrCode = '0' THEN Customeraddress.countrycode
ELSE Deliveryaddress.countrycode
END AS delivery_country
FROM Salesorder
LEFT JOIN Customeraddress ON Customeraddress.CustID = Salesorder.CustID
LEFT JOIN Deliveryaddress ON Deliveryaddress.CustID = Salesorder.CustID
AND Deliveryaddress.DelAddrCode = Salesorder.DelAddrCode
) t
LEFT JOIN Country ON country.countrycode = t.delivery_country;
Outer join the address tables and see which one matches with COALESCE:
SELECT
DelAddrCode,
COALESCE(ca.countrycode, da.countrycode) AS countrycode,
c.description
FROM Salesorder so
LEFT JOIN Customeraddress ca ON ca.CustID = so.CustID AND so.DelAddrCode = 0
LEFT JOIN Deliveryaddress da ON da.CustID = so.CustID AND da.DelAddrCode = so.DelAddrCode
JOIN country c ON c.countrycode = COALESCE(ca.countrycode, da.countrycode);
If Deliveryaddress.DelAddrCode cannot be 0 (which I assume), you can even make this
JOIN country c ON c.countrycode IN (ca.countrycode, da.countrycode);
which may lead to a better execution plan for being a simpler link.

Only return value that matches the ID on table 1

I have tried all possible joins and sub-queries but I cant get the data to only return one value from table 2 that exactly matches the vendor ID. If I dont have the address included in the query, I get one hit for the vendor ID. How can I make it so that when I add the address, I only want the one vendor that I get prior to adding the address.
The vendor from table one must be VEN-CLASS IS NOT NULL.
This was my last attempt using subquery:
SELECT DISTINCT APVENMAST.VENDOR_GROUP,
APVENMAST.VENDOR,
APVENMAST.VENDOR_VNAME,
APVENMAST.VENDOR_CONTCT,
APVENMAST.TAX_ID,
Subquery.ADDR1
FROM (TEST.dbo.APVENMAST APVENMAST
INNER JOIN
(SELECT APVENADDR.ADDR1,
APVENADDR.VENDOR_GROUP,
APVENADDR.VENDOR,
APVENMAST.VEN_CLASS
FROM TEST.dbo.APVENADDR APVENADDR
INNER JOIN TEST.dbo.APVENMAST APVENMAST
ON (APVENADDR.VENDOR_GROUP = APVENMAST.VENDOR_GROUP)
AND (APVENADDR.VENDOR = APVENMAST.VENDOR)
WHERE (APVENMAST.VEN_CLASS IS NOT NULL)) Subquery
ON (APVENMAST.VENDOR_GROUP = Subquery.VENDOR_GROUP)
AND (APVENMAST.VENDOR = Subquery.VENDOR))
INNER JOIN TEST.dbo.APVENLOC APVENLOC
ON (APVENMAST.VENDOR_GROUP = APVENLOC.VENDOR_GROUP)
AND (APVENMAST.VENDOR = APVENLOC.VENDOR)
WHERE (APVENMAST.VEN_CLASS IS NOT NULL)
Try this:
SELECT APVENMAST.VENDOR_GROUP
, APVENMAST.VENDOR
, APVENMAST.VENDOR_VNAME
, APVENMAST.VENDOR_CONTCT
, APVENMAST.TAX_ID
, APVENADDR.ADDR1
FROM TEST.dbo.APVENMAST APVENMAST
INNER JOIN (
select VENDOR_GROUP, VENDOR, ADDR1
, row_number() over (partition by VENDOR_GROUP, VENDOR order by ADDR1) r
from TEST.dbo.APVENADDR
) APVENADDR
ON APVENADDR.VENDOR_GROUP = APVENMAST.VENDOR_GROUP
AND APVENADDR.VENDOR = APVENMAST.VENDOR
AND APVENADDR.r = 1
--do you need this table; you're not using it...
--INNER JOIN TEST.dbo.APVENLOC APVENLOC
--ON APVENMAST.VENDOR_GROUP = APVENLOC.VENDOR_GROUP
--AND APVENMAST.VENDOR = APVENLOC.VENDOR
WHERE APVENMAST.VEN_CLASS IS NOT NULL
--if the above inner join was to filter results, you can do this instead:
and exists (
select top 1 1
from TEST.dbo.APVENLOC APVENLOC
ON APVENMAST.VENDOR_GROUP = APVENLOC.VENDOR_GROUP
AND APVENMAST.VENDOR = APVENLOC.VENDOR
)
I found another column in the APVENLOC table that I can filter on to get the unique vendor. Turns out if the vendor address is for the main office, the vendor location is set blank.
Easier than I thought it would be!
SELECT DISTINCT APVENMAST.VENDOR_GROUP,
APVENMAST.VENDOR,
APVENMAST.VENDOR_VNAME,
APVENADDR.ADDR1,
APVENMAST.VENDOR_SNAME,
APVENADDR.LOCATION_CODE,
APVENMAST.VEN_CLASS
FROM TEST.dbo.APVENMAST APVENMAST
INNER JOIN TEST.dbo.APVENADDR APVENADDR
ON (APVENMAST.VENDOR_GROUP = APVENADDR.VENDOR_GROUP)
AND (APVENMAST.VENDOR = APVENADDR.VENDOR)
WHERE (APVENADDR.LOCATION_CODE = ' ')
Shaji

How to select a single row where multiple rows exist from a table

I have two tables th_Therapy_Note and th_Approved. When a note in th_Therapy_Note gets approved, the application inserts a record to th_Approved.
A note can get rejected for several reasons after it has been approved (don't ask me why, as I did not design this app, lol). So if a note is rejected after being approved, another entry to th_Approved is inserted.
th_Approved.th_approved_isApproved is a boolean (bit) column, so depending on the status, the note entry in this table for this column in true or false
So multiple lines for the same note can exist in th_Approved with different th_Approved.th_approved_isApproved status, the last entry being the most recent one and correct status
The main purpose for the below query is to select notes that are ready to be 'finalized'. The issue with the below query is in the last inner join filter 'AND th_Approved.th_approved_isApproved = 1' This is selecting notes that effectively have been approved, meaning they should have an entry in th_Approved and th_Approved.th_approved_isApproved is true.
This works perfect for notes with single entries in th_Approved, but notes with multiple entries in th_Approved (as explained above) represent an issue if the last entry for that particular note is false. The query will still pick it up because there is at least one entry with th_Approved.th_approved_isApproved as true, even when last correct status is false. I need to only look at this last entry to be able to determine the correct status for a note and select it or not depending on the status.
Last part of the query (and th_Therapy_Note.th_note_id=16239) is just for my testing as this note has multiple entries, but the final will not have this.
How can I solve my issue? I have been looking at several strategies with no luck.....Hopefully I made sense :) thanks
SELECT Distinct Convert(varchar,th_Therapy_Note.th_note_id) as NOTEID, '054' as PROGCODE, Rtrim(ch.child_caseNumber) as CASEID,
Case th_TherapyType.shortname when 'ST' then 'SP' else rtrim(th_TherapyType.shortname) end as SERVTYPE, Convert(varchar,th_Therapy_Note.th_note_dateofservice,101) as DELSERVDATE,
Cast(((Select sum(th_TherapyServiceProvided.units) From th_TherapyServiceProvided where th_DirectServices.th_ds_id = th_TherapyServiceProvided.th_ds_id)/60) as varchar) as SERVHRS,
Cast(((Select sum(th_TherapyServiceProvided.units) From th_TherapyServiceProvided where th_DirectServices.th_ds_id = th_TherapyServiceProvided.th_ds_id)%60) as varchar) as SERVMIN,
'1' as METHOD, isnull(th_Users.trad_id, ' ') as SPROVNUM, th_Users.th_user_lname, '' as COVISIT
FROM th_Therapy_Note INNER JOIN
child_tbl AS ch ON th_Therapy_Note.child_id = ch.child_recordId INNER JOIN
th_DirectServices ON th_Therapy_Note.th_note_id = th_DirectServices.th_note_id INNER JOIN
LookUp_contactType ON th_Therapy_Note.contact_type_id = LookUp_contactType.recId INNER JOIN
th_Users ON th_Therapy_Note.service_coordinator = th_Users.th_user_email INNER JOIN
th_TherapyType ON th_Therapy_Note.therapy_type = th_TherapyType.id INNER JOIN
th_Approved ON th_Therapy_Note.th_note_id = th_Approved.th_note_id AND th_Approved.th_approved_isApproved = 1
WHERE (ch.child_recordId =
(SELECT MAX(child_recordId) AS Expr1
FROM child_tbl
WHERE (child_caseNumber = ch.child_caseNumber)))
and th_Therapy_Note.th_note_dateofservice > '4/22/2014' and th_Therapy_Note.th_note_id=16239
You can use a "MAX" trick (or "MIN" or similar). On a date or unique column is typical.
Here is a generic Northwind example that uses the MAX(OrderDate) (where a customer has more than one order).
The logic below falls apart if there are 2 orders with the same order-date, and those dates are the "max" date. So a unique identifier that is orderable is preferred)
Use Northwind
GO
Select cust.* , ords.*
from dbo.Customers cust
LEFT OUTER JOIN dbo.Orders ords
ON
(
ords.CustomerID = cust.CustomerID
AND ords.OrderDate =
(SELECT MAX(OrderDate)
FROM dbo.Orders innerords
WHERE innerords.CustomerID = cust.CustomerID
)
)
where cust.CustomerID = 'ALFKI'
Since you have a sequential ID on th_Approved, then I'd use that. Integer comparison on id is perfect. Date/Datetime comparison can sometimes add problems.
So I'd try this:
SELECT Distinct
Convert(varchar,th_Therapy_Note.th_note_id) as NOTEID,
'054' as PROGCODE,
Rtrim(ch.child_caseNumber) as CASEID,
Case th_TherapyType.shortname
when 'ST' then 'SP'
else rtrim(th_TherapyType.shortname)
end as SERVTYPE,
Convert(varchar,th_Therapy_Note.th_note_dateofservice,101) as DELSERVDATE,
Cast(((
Select sum(th_TherapyServiceProvided.units)
From th_TherapyServiceProvided
where th_DirectServices.th_ds_id = th_TherapyServiceProvided.th_ds_id)/60) as varchar
) as SERVHRS,
Cast(((
Select sum(th_TherapyServiceProvided.units)
From th_TherapyServiceProvided
where th_DirectServices.th_ds_id = th_TherapyServiceProvided.th_ds_id)%60) as varchar
) as SERVMIN,
'1' as METHOD,
isnull(th_Users.trad_id, ' ') as SPROVNUM,
th_Users.th_user_lname, '' as COVISIT
FROM th_Therapy_Note
INNER JOIN child_tbl AS ch ON th_Therapy_Note.child_id = ch.child_recordId
INNER JOIN th_DirectServices ON th_Therapy_Note.th_note_id = th_DirectServices.th_note_id INNER JOIN LookUp_contactType ON th_Therapy_Note.contact_type_id = LookUp_contactType.recId INNER JOIN th_Users ON th_Therapy_Note.service_coordinator = th_Users.th_user_email
INNER JOIN th_TherapyType ON th_Therapy_Note.therapy_type = th_TherapyType.id
INNER JOIN th_Approved ON th_Approved.th_approved_id=(
SELECT MAX(th_approved_id)
FROM th_Approved
WHERE th_Therapy_Note.th_note_id = th_Approved.th_note_id)
WHERE ch.child_recordId = (
SELECT MAX(child_recordId)
FROM child_tbl
WHERE child_caseNumber = ch.child_caseNumber)
AND th_Therapy_Note.th_note_dateofservice > '4/22/2014'
AND th_Approved.th_approved_isApproved = 1
AND th_Therapy_Note.th_note_id=16239
Without access to your dataset to test this with this is the best I can give you.
In essence what I am doing is filtering out the duplicates using a CTE and the TSQL command ROW NUMBER using whatever date function you have. then placing the filtered out list into your main query.
;with fixDuplicateCTE(
SELECT m.th_note_id, m.tag
FROM ( SELECT TH_NOTE_ID ROW_NUMBER OVER(partition by th_note_id ORDER BY [SOME DATE FUNCTION YOU HAVE!!!!!] desc) as tag FROM th_approved) as m
INNER JOIN th_approved AS a on m.th_note_id = a.th_note_id
WHERE m.tag = 1
)
SELECT Distinct Convert(varchar,th_Therapy_Note.th_note_id) as NOTEID, '054' as PROGCODE, Rtrim(ch.child_caseNumber) as CASEID,
Case th_TherapyType.shortname
when 'ST' then 'SP' else rtrim(th_TherapyType.shortname) end as SERVTYPE, Convert(varchar,th_Therapy_Note.th_note_dateofservice,101) as DELSERVDATE,
Cast(((Select sum(th_TherapyServiceProvided.units) From th_TherapyServiceProvided where th_DirectServices.th_ds_id = th_TherapyServiceProvided.th_ds_id)/60) as varchar) as SERVHRS,
Cast(((Select sum(th_TherapyServiceProvided.units) From th_TherapyServiceProvided where th_DirectServices.th_ds_id = th_TherapyServiceProvided.th_ds_id)%60) as varchar) as SERVMIN,
'1' as METHOD, isnull(th_Users.trad_id, ' ') as SPROVNUM, th_Users.th_user_lname, '' as COVISIT
FROM th_Therapy_Note
INNER JOIN child_tbl AS ch ON th_Therapy_Note.child_id = ch.child_recordId
INNER JOIN th_DirectServices ON th_Therapy_Note.th_note_id = th_DirectServices.th_note_id
INNER JOIN LookUp_contactType ON th_Therapy_Note.contact_type_id = LookUp_contactType.recId
INNER JOIN th_Users ON th_Therapy_Note.service_coordinator = th_Users.th_user_email
INNER JOIN th_TherapyType ON th_Therapy_Note.therapy_type = th_TherapyType.id
INNER JOIN fixDuplicateCTE ON th_Therapy_Note.th_note_id = th_Approved.th_note_id AND th_Approved.th_approved_isApproved = 1
WHERE (ch.child_recordId =
(SELECT MAX(child_recordId) AS Expr1
FROM child_tbl
WHERE (child_caseNumber = ch.child_caseNumber)))
and th_Therapy_Note.th_note_dateofservice > '4/22/2014' and th_Therapy_Note.th_note_id=16239

MS SQL Conditional Join

I have a SQL Query :
SELECT * FROM Customer c
LEFT JOIN Invoice I ON I.InvcNum = C.Cust_InvcNum
some thing changed and the join does not work because there is no consistency in the data in the 'Cust_InvcNum'. So now when it does not find the record for the join or if it is null it needs to check for another condition.
LEFT JOIN Invoice I ON I.InvcNum = (SELECT p.InvcPrefix FROM Prefix WHERE p.DealerID = I.DealrID ) + '-' + I.InvcNum
second join I do works but it is taking too long for it get me data. Is there any other way to do this.
Earlier it used to be
Join on I.InvcNum = C.Cust_InvcNum
both the columns has the same data like DlrCd-InvcNum i.e both the columns 1234-A789
but not it could match on the above data or now the column 'InvcNum' in invoice table
can be populated like Dlrd-InvcNum or InvcPrefix-InvcNum
So InvcNum = 1234-A789 but CustNum = I94-A789
so we need to check if the for InvoicePrefix-InvcNum
SELECT *
FROM Customer c
LEFT JOIN (
SELECT i.InvcNum, p.InvcPrefix + '-' + I.InvcNum AS pInvcNum
FROM Invoice i LEFT JOIN Prefix p ON i.DealrID = p.DealrID
) ip ON c.Cust_InvcNum = CASE WHEN c.Cust_InvcNum = ip.InvcNum
THEN ip.InvcNum
ELSE ip.pInvcNum END