SQL Server - How to do Inner Join when condition could be empty? - sql

I am trying to get the Country from my factories AddressID directly in one Query with an Inner join. My problem is that the AddressID could be an empty string.
How do i check that and do some kind of exception or something similar? I if address ID is empty i need an empty string as result for f.Country.
This is my query for now, but if AddressID = '' then the row is not showing up in my result.
SELECT o.FactoryID,o.Name,o.Rating,o.ProductCategory,o.Emissions,o.LatestChanges,o.AddressID,o.ProductTags,f.Country
FROM FactoryHistory o
INNER JOIN AddressHistory f on f.AddressID = o.AddressID
WHERE NOT o.LatestChanges = 'Deleted' AND o.IsCurrent = 1 AND f.IsCurrent = 1
I something in my question is missing or unclear, just let me know!

Just left join:
SELECT o.FactoryID, o.Name, o.Rating, o.ProductCategory, o.Emissions, o.LatestChanges, o.AddressID, o.ProductTags, f.Country
FROM FactoryHistory o
LEFT JOIN AddressHistory f on f.AddressID = o.AddressID AND f.IsCurrent = 1
WHERE NOT o.LatestChanges = 'Deleted' AND o.IsCurrent = 1
If you still want to filter out factories whose AddressID is not null (assuming that by empty you mean null) and that do not exist in the address table, than you can add a condition in the WHERE clause:
WHERE
NOT o.LatestChanges = 'Deleted'
AND o.IsCurrent = 1
AND (o.AddressID IS NULL OR f.AddressID IS NOT NULL)
It might be clearer with a negation:
WHERE
NOT o.LatestChanges = 'Deleted'
AND o.IsCurrent = 1
AND NOT (o.AddressID IS NOT NULL AND f.AddressID IS NULL)

Related

SQL Query to apply join on basis of case Condition

I have a requirement where I need to fetch the Dimension Key of Region table on basis of the following preference.
Fetch dimension key on basis of Zipcode of Physical address(PA)
If the first condition is not satisfied that fetch dimension key on basis of the Zip Code of the Mailing address
If the second condition is also not satisfied than fetch the dimension key on basis of the Parish Code of Physical address
Else fetch dimension key on basis of parish Code of Mailing address.
I am trying to use the below query but is giving multiple records since all left joins are getting evaluated. I want that it should not go on the second condition if the first condition is satisfied.
select REGION_DIM_SK, CASE_NUM
from (
select distinct COALESCE(RDIM.REGION_DIM_SK, RDIM1.REGION_DIM_SK, RDIM2.REGION_DIM_SK, RDIM3.REGION_DIM_SK) AS REGION_DIM_SK
, DC.CASE_NUM, ADDR_TYPE_CD
FROM rpt_dm_ee_intg.CASE_PERSON_ADDRESS dc
left join rpt_dm_ee_prsnt.REGION_DIM RDIM on dc.ZIP_CODE = RDIM.ZIP_CODE and RDIM.REGION_EFF_END_DT IS NULL and dc.addr_type_cd='PA' AND dc.EFF_END_DT IS NULL
left join rpt_dm_ee_prsnt.REGION_DIM RDIM1 ON dc.ZIP_CODE = RDIM1.ZIP_CODE AND RDIM1.REGION_EFF_END_DT IS NULL AND dc.addr_type_cd='MA' AND DC.EFF_END_DT IS NULL
left join (
select PARISH_CD, min(REGION_DIM_SK) as REGION_DIM_SK
from rpt_dm_ee_prsnt.REGION_DIM
where REGION_EFF_END_DT is null
group by PARISH_CD
) RDIM2 ON dc.addr_type_cd='PA' and dc.PARISH_CD = RDIM2.PARISH_CD AND DC.EFF_END_DT IS NULL
left join (
select PARISH_CD, min(REGION_DIM_SK) as REGION_DIM_SK
from rpt_dm_ee_prsnt.REGION_DIM
where REGION_EFF_END_DT is null
group by PARISH_CD
) RDIM3 ON dc.addr_type_cd='MA' and dc.PARISH_CD = RDIM3.PARISH_CD AND DC.EFF_END_DT IS NULL
) A
where REGION_DIM_SK is not null
) RD on RD.case_num = rpt_dm_ee_intg.CASE_PERSON_ELIGIBILITY.CASE_NUM
Use multiple left joins. Your query is rather hard to follow -- it has other tables and references not described in the problem.
But the idea is:
select t.*,
coalesce(rpa.dim_key, rm.dim_key, rpap.dim_key, rmp.dim_key) as dim_key
from t left join
dim_region rpa
on t.physical_address_zipcode = rpa.zipcode left join
dim_region rm
on t.mailing_address_zipcode = rm.zipcode and
rpa.zipcode is null left join
dim_region rpap
on t.physical_addresss_parishcode = rpap.parishcode and
rm.zipcode is null left join
dim_region rmp
on t.physical_addresss_parishcode = rmp.parishcode and
rpap.zipcode is null
The trick is to put the conditions in CASE WHEN:
SELECT *
FROM table1 a
JOIN table2 b
ON CASE
WHEN a.code is not null and a.code = b.code THEN 1
WHEN a.type = b.type THEN 1
ELSE 0
END = 1
For your example you can reduce the code to just two joins, it can't be done in one as you are joining two different tables.
SELECT CASE WHEN RDIM.addres IS NULL THEN RDIM2.addres ELSE RDIM.addres
FROM rpt_dm_ee_intg.CASE_PERSON_ADDRESS dc
LEFT JOIN rpt_dm_ee_prsnt.REGION_DIM RDIM ON CASE
WHEN (dc.ZIP_CODE = RDIM.ZIP_CODE
AND RDIM.REGION_EFF_END_DT IS NULL
AND dc.addr_type_cd='PA'
AND dc.EFF_END_DT IS NULL) THEN 1
WHEN (dc.ZIP_CODE = RDIM1.ZIP_CODE
AND RDIM1.REGION_EFF_END_DT IS NULL
AND dc.addr_type_cd='MA'
AND DC.EFF_END_DT IS NULL) THEN 1
ELSE 0
END = 1
LEFT JOIN
(SELECT PARISH_CD,
min(REGION_DIM_SK) AS REGION_DIM_SK
FROM rpt_dm_ee_prsnt.REGION_DIM
WHERE REGION_EFF_END_DT IS NULL
GROUP BY PARISH_CD) RDIM2 ON CASE
WHEN (dc.addr_type_cd='PA'
AND dc.PARISH_CD = RDIM2.PARISH_CD
AND DC.EFF_END_DT IS NULL
AND RDIM.ZIP_CODE IS NULL) THEN 1
WHEN (dc.addr_type_cd='MA'
AND dc.PARISH_CD = RDIM3.PARISH_CD
AND DC.EFF_END_DT IS NULL
AND RDIM.ZIP_CODE IS NULL) THEN 1
ELSE 0
END = 1
edit
If you don't want to have nulls from RDIM2 table if RDIM1 zip code is present the logic could be easily extended to support that. You just need to add AND RDIM.ZIP_CODE IS NULL to CASE WHEN conditions.

DB2 Update with subquery that contains join - correlating

I am trying to perform an update with a subquery where the update table is joined in the subquery. I cannot figure out how to associate the update record with the record found in the subquery. Something like the following, though as written this will obviously update the entire table. Thanks in advance.
Update OPTION OPT
SET (PSTREET, PCITY, PPROVINCE, PCOUNTRY, PPOSTALCODE)=
(select ADDRESS, CITY, PROVSTATE, COUNTRY, POSTALCODE
from ADDRESSES addr INNER JOIN COMPANY C ON C.SECURITYCOMPANY = addr.CODE1 || addr.CODE2
INNER JOIN DCODE D ON C.COMPANY_ID = D.COMPANY_ID
INNER JOIN OPTION OPT ON OPT.DCODE_ID = D.DCODE_ID
WHERE C.YEAROF IS NULL
AND C.DELETED IS NULL
AND D.DCODEEFF < CURRENT TIMESTAMP
AND (D.DCODEEXP IS NULL OR D.DCODEEXP > CURRENT TIMESTAMP)
AND D.DCODEELEMENT = addr.DCODEELEMENT
AND D.IND = addr.IND
AND ((addr.IND = 'B' AND addr.VAL1 = OPT.VAL1 AND addr.VAL2 = OPT.VAL2)
OR (addr.IND = 'Y' AND addr.VAL2 = OPT.VAL2)
OR (addr.IND = 'X' AND addr.VAL1 = OPT.VAL1))
You need to have some criteria to identify the records in OPT that you want to update. If its a single record, you'll need a surrogate or natural key. If its a many records like, say, based on a timestamp, you will need that time. Those criteria can then be put into a where clause after your set.
Use a condition in the WHERE clause in the sub-query that ties the result(s) in the sub-query to the outer table that you're updating. Here I added AND addr.addr_id = OPT.addr_id to your WHERE clause, but whatever the id column is called it needs to be shared between the table that you are updating and the sub-query.
UPDATE OPTION OPT
SET (PSTREET, PCITY, PPROVINCE, PCOUNTRY, PPOSTALCODE) =
(SELECT ADDRESS, CITY, PROVSTATE, COUNTRY, POSTALCODE
FROM ADDRESSES addr INNER JOIN COMPANY C ON C.SECURITYCOMPANY = addr.CODE1 || addr.CODE2
INNER JOIN DCODE D ON C.COMPANY_ID = D.COMPANY_ID
INNER JOIN OPTION OPT ON OPT.DCODE_ID = D.DCODE_ID
WHERE C.YEAROF IS NULL
AND C.DELETED IS NULL
AND D.DCODEEFF < CURRENT TIMESTAMP
AND (D.DCODEEXP IS NULL OR D.DCODEEXP > CURRENT TIMESTAMP)
AND D.DCODEELEMENT = addr.DCODEELEMENT
AND D.IND = addr.IND
AND ((addr.IND = 'B' AND addr.VAL1 = OPT.VAL1 AND addr.VAL2 = OPT.VAL2)
OR (addr.IND = 'Y' AND addr.VAL2 = OPT.VAL2)
OR (addr.IND = 'X' AND addr.VAL1 = OPT.VAL1)
AND addr.addr_id = OPT.addr_id)
In reality the criteria might be more complicated (involving a compound key or some inequality condition, for instance) - but regardless, adding the condition to the inner query is what's required.

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

Need to create a report for contacts that have missed workflow activities

We had an issue where our workflows have not been creating activities.
I now need to report which accounts have not had their workflows invoked.
I've tried advanced find and then moved to sql.
My question is can someone provide a simple starter query to pull which 'entity' has NOT had a specific activity associated with it?
Please let me know if the question is not clear enough or more info, is needed.
Below is a solution using SQL where I step through my thought process, and below that is a solution that gets started with the C# API (edit: just realized this is for a report, so that part can be disregarded). I've commented in most places, so I hope my methods are fairly straightforward.
SQL
1.
--get all the entities that aren't activities and aren't intersect entities (N:N tables)
--Put in your own where conditions to further filter this list,
--which is still probably far too expansive
SELECT
A.name EntityName
FROM MetadataSchema.Entity A
WHERE
A.IsActivity = 0
AND A.IsIntersect = 0
2.
--CROSS JOIN the non-activity entities with the activity entities
--to get a list of all possible entity/activity pairings
SELECT DISTINCT
A.name EntityName
, B.Name ActivityName
FROM MetadataSchema.Entity A
CROSS JOIN MetadataSchema.Entity B
WHERE
A.IsActivity = 0
AND A.IsIntersect = 0
AND B.IsActivity = 1
3.
--LEFT JOIN the partial cartesian join above against the Activity table,
--making a note of which entities actually have activity records.
--This will provide a complete list of which entity/activity pairings
--exist and don't exist
SELECT
A.name EntityName
, B.Name ActivityName
--if there is a matching activity, the unique key,
--ActivityTypeCode (int), will be positive.
--So, if there is a positive sum for an entity/activity
--pairing, you know there is a valid pair; otherwise
--no pair
, CAST(CASE WHEN sum(coalesce(C.ActivityTypeCode, 0)) > 0
THEN 1
ELSE 0
END AS BIT) EntityOwnsActivity
FROM MetadataSchema.Entity A
CROSS JOIN MetadataSchema.Entity B
LEFT JOIN dbo.ActivityPointer C ON
--ObjectTypeCode is a unique identifier for Entities;
--RegardingObjectTypeCode is the code for the entity type
--associated with a particular activity
A.ObjectTypeCode = C.RegardingObjectTypeCode
--ActivityTypeCode is the code for the particular activity
AND B.ObjectTypeCode = C.ActivityTypeCode
WHERE
A.IsActivity = 0
AND A.IsIntersect = 0
AND B.IsActivity = 1
GROUP BY
A.name
, B.Name
4.
--Putting it all together, using the above master table,
--filter out the entities/activities you're interested in
--(in this case, all entities that aren't associated with
--any emails)
SELECT
EntityName
FROM
(
SELECT
A.name EntityName
, B.Name ActivityName
, CAST(CASE WHEN sum(coalesce(C.ActivityTypeCode, 0)) > 0
THEN 1
ELSE 0
END AS BIT) EntityOwnsActivity
FROM MetadataSchema.Entity A
CROSS JOIN MetadataSchema.Entity B
LEFT JOIN dbo.ActivityPointer C ON
A.ObjectTypeCode = C.RegardingObjectTypeCode
AND B.ObjectTypeCode = C.ActivityTypeCode
WHERE
A.IsActivity = 0
AND A.IsIntersect = 0
AND B.IsActivity = 1
GROUP BY
A.name
, B.Name
) EntityActivities
WHERE ActivityName = 'Email'
AND EntityOwnsActivity = 0
ORDER BY
EntityName
C#.NET API
using (OrganizationServiceProxy _serviceProxy =
new OrganizationServiceProxy(
new Uri(".../XRMServices/2011/Organization.svc"), null, null, null))
{
_serviceProxy.EnableProxyTypes();
RetrieveAllEntitiesRequest request = new RetrieveAllEntitiesRequest()
{
EntityFilters = EntityFilters.Entity,
RetrieveAsIfPublished = true
};
// Retrieve the MetaData.
EntityMetadata[] entities =
((RetrieveAllEntitiesResponse)_serviceProxy.Execute(request)).EntityMetadata;
var ents = from e1 in entities.Where(x => x.IsActivity != true)
.Where(x => x.IsIntersect != true)
from e2 in entities.Where(x => x.IsActivity == true)
select new
{
entityName = e1.SchemaName
,
activityName = e2.SchemaName
};
//at this point, because of the limited nature of the Linq provider for left joins
//and sums, probably the best approach is to do a fetch query on each entity/activity
//combo, do some sort of sum and find out which combos have matches
// in the activity pointer table
//API = very inefficient; maybe improved in next CRM release? Let's hope so!
}

updating Table from Another Table with Criteria

i am trying to write a query that will update the schemeid of a row with the id of the matching row from another table.
tblschemes b holds the schemes detail and tblclaims_liberty a holds the claims data and the fields to join on are b.nett_scheme = a.schemename and a.agentcode = b.agentcode
why then id the query below allocating a schemeid to rows of data that do not match the agentcode??
update tblclaims_liberty
set tblclaims_liberty.schemeid = tblschemes.id
from tblschemes inner join tblclaims_liberty on tblclaims_liberty.schemename = tblschemes.nett_scheme and tblclaims_liberty.agentcode = tblschemes.agentcode
where
ce_report = 'yes'
and (tblclaims_liberty.schemeid != tblschemes.id or schemeid is null) --only updates rows that require updateing instead of 6mil+ lines of data.
can someone point me in the right direction?? why is it not recognising the agentcode match?
regards,
Adam
Try with this:
update tblclaims_liberty TLtoUpdate
set TLtoUpdate.schemeid =
(
select TS.id
from tblschemes TS inner join tblclaims_liberty TL on TL.schemename = TS.nett_scheme and TL.agentcode = TS.agentcode
where TL.schemeid = TLtoUpdate.schemeid
)
where TLtoUpdate.ce_report = 'yes' and TLtoUpdate.schemeid is null
Looks there was missing the TL.id condition in the subquery.