is there a way to update a column using multiple tables - sql

I'm trying to update a column called Specialty in a table called #LIST. I need to pull information from 3 different tables incase the specialty in 1 table is NULL. I prefer to use the specialty from the #Segment table, if that's NULL then I want to use the specialty from the #SUBMARKET table, and if that's NULL I want to use the specialty from the #MARKET table.
When I run the below query, it doesn't update any rows. I don't want to use more than 1 Update statement. What can I do?
UPDATE #LIST
SET Specialty = CASE WHEN (l.Segment__c is not NULL) THEN s.Specialty
WHEN (l.Segment__c is NULL) THEN b.Specialty
WHEN (l.Submarket__c is NULL) THEN m.Specialty
ELSE s.Specialty
END
FROM #LIST l
join #MARKET m on m.Market = l.Market__c
join #SUBMARKET b on b.Submarket = l.Submarket__c
join #Segment s on s.Segment = l.Segment__c

You need to use the table alias in the UPDATE. Also, I think you need left join:
UPDATE l
SET Specialty = CASE WHEN (l.Segment__c is not NULL) THEN s.Specialty
WHEN (l.Segment__c is NULL) THEN b.Specialty
WHEN (l.Submarket__c is NULL) THEN m.Specialty
ELSE s.Specialty
END
FROM #LIST l
left join #MARKET m on m.Market = l.Market__c
left join #SUBMARKET b on b.Submarket = l.Submarket__c
left #Segment s on s.Segment = l.Segment__c;
Otherwise, the NULL values will filter out rows, because they do not match in the join.

Related

Trying to update a field conditionally in SQL Stored Procedure

I have a procedure that populates two sets of application information into the same fields. First the fields are filled out with applicable accounts from group "A" and then the same process happens for group "B" accounts.
Most of the group B fields are filled in by a insert/select statement. However, the query to select "account number" is a little more complex and that is in an UPDATE statement. I will paste the code below but I cannot get it to properly update the rows (for group B) with account numbers, despite the fact the query works on its own outside the procedure (essentially, the account numbers do exist).
Any idea why? I tried adding a case statement to single out group B rows (the where clause is hardcoded for group B... e.g. clfcode = 3) but that didn't work. Let me know if you need more information. I haven't much experience with update statements in stored procedures.
update src
set account_key = case when src.clfcode = 3 and src.branch_key = 12 then a.account_key else src.account_key end
from #src_table src
inner join SDFDW_Landing.cu.FICS_ms_Investor_Loan l
on l.loan_id = src.application_number
left join dm.dim_product p
on p.product_key = src.product_key
left join (
Select Distinct t.PARENTACCOUNT, t.USERCHAR1 as loan_id
from SDFDW_Landing.dbo.tracking t
where t.TYPE = 1
and t.ProcessDate = #v_max_last_processed_date
and t.USERCHAR1 is not null
) t on t.loan_id = l.loan_id
left join dm.dim_account a
on t.PARENTACCOUNT = a.account_nkey
WHERE p.bdw_report_category = 'Mortgage'
and l.processdate = #v_max_last_processed_date
The join on a subquery might cause the issue. You could try to replace it with an apply and see if that helps.
update
src
set
account_key =
case
when
src.clfcode = 3
and src.branch_key = 12
then
a.account_key
else
src.account_key
end
from
#src_table src
inner join
SDFDW_Landing.cu.FICS_ms_Investor_Loan l
on l.loan_id = src.application_number
left join
dm.dim_product p
on p.product_key = src.product_key
outer apply (
Select
acc.*
from
dm.dim_account acc
inner join
SDFDW_Landing.dbo.tracking t
on acc.account_nkey = t.parentaccount
where
t.TYPE = 1
and t.ProcessDate = #v_max_last_processed_date
and t.USERCHAR1 is not null
and t.loan_id = l.loan_id
) a
WHERE
p.bdw_report_category = 'Mortgage'
and l.processdate = #v_max_last_processed_date
alternatively since you are already within a stored procedure, I'd populate a temp table with the data from your subquery and simply join on that temp table from your update statement.

SQL Oracle Update containing left join

I want to perform an update for the results of a select query.
SELECT
a.reason,
n.note
FROM applications a
LEFT JOIN notes n on n.app_id = a.app_id
AND n.note LIKE '%old%'
WHERE a.code = 'run' AND a.reason IS NULL
I thought I could perform these updates separately wrapping the select in an update however I get the error ORA-01733: virtual column not allowed here. How can I go about performing these updates?
UPDATE (
SELECT
a.reason AS Reason
FROM applications a
LEFT JOIN notes n on n.app_id = a.app_id
AND n.note LIKE '%old%'
WHERE a.code = 'run' AND a.reason IS NULL
) SET Reason = null
UPDATE (
SELECT
n.note AS Note
FROM applications a
LEFT JOIN notes n on n.app_id = a.app_id
AND n.note LIKE '%old%'
WHERE a.code = 'run' AND a.reason IS NULL
) SET Note = null
You can't update the two tables at the same time. You need two different update statements as follows:
Updating the APPLICATIONS table is quite easy as all the records of the APPLICATIONS table having a.code = 'run' AND a.reason IS NULL will be there in your SELECT query.
UPDATE APPLICATIONS A
SET
REASON = NULL
WHERE A.CODE = 'run'
AND A.REASON IS NULL;
To update the NOTES table, you can use the EXISTS clause as follows:
UPDATE NOTES N
SET
NOTE = NULL
WHERE EXISTS (
SELECT 1
FROM APPLICATIONS A
WHERE N.APP_ID = A.APP_ID
AND A.CODE = 'run'
AND A.REASON IS NULL
)
AND N.NOTE LIKE '%old%'
You must update the NOTES table first and then APPLICATIONS table as while updating the NOTES table you are using the condition A. REASON IS NULL but while updating the APPLICATIONS table, you are updating the REASON column.

Multiple where exists

I need to update value_check column in table_work as N based on below conditions
Update value_check as N
if employee_id in table_work has no employee_manager_id record
(either blank/null or no record at all) in employees_contact table
when getdate is between contact_eff_dt and contact_end_dt (join
using employee_id)
if employee_id in table_work has a record in
employees_contact table but employee_manager_id work_location_state
is not NJ or NY or ME ..mgr_work_location table has
employee_manager_id and work_location_state columns.
I am able to do it with 2 update statements bit is there a simple way to use only one update statement? Maybe using multiple where exists conditions?
Here are the 2 updates I use now:
UPDATE 1
Update work
set work.value_check = 'N'
From table_work work
Where wotk.value_check = 'Y'
And not exists (select employee_manager_id
from employees_contact contact
Where contact.employee_id = work.employee_id
And getdate() between contact.eff_dt and contact.end_dt)
UPDATE 2
Update work
set work.value_check = 'N'
From table_work work
Join employees_contact contact On contact.employee_id= work.employee_id
Join mgr_work_location mgr On mgr.mgr_id = contact.employee_manager_id
Where work.value_check = 'Y'
And getdate() between contact.eff_dt
and contact.end_dt And mgr.work_location_state not in ('NJ','NY,'ME')
The first query's NOT EXISTS criteria can probably be emulated in the second query via a LEFT JOIN, and check for contact.employee_id IS NULL (the unmatched)
And those limits on contact.eff_dt can be moved from the WHERE to that LEFT JOIN on mgr_work_location.
A test on rextester here
UPDATE work
SET work.value_check = 'N'
FROM table_work work
LEFT JOIN employees_contact contact
ON contact.employee_id = work.employee_id
AND contact.eff_dt <= getdate()
AND contact.end_dt >= getdate()
LEFT JOIN mgr_work_location mgr
ON mgr.mgr_id = contact.employee_manager_id
WHERE work.value_check = 'Y'
AND (contact.employee_id IS NULL
OR mgr.work_location_state NOT IN ('NJ','NY','ME'))

How can I perform the Count function with a where clause?

I have my database setup to allow a user to "Like" or "Dislike" a post. If it is liked, the column isliked = true, false otherwise (null if nothing.)
The problem is, I am trying to create a view that shows all Posts, and also shows a column with how many 'likes' and 'dislikes' each post has. Here is my SQL; I'm not sure where to go from here. It's been a while since I've worked with SQL and everything I've tried so far has not given me what I want.
Perhaps my DB isn't setup properly for this. Here is the SQL:
Select trippin.AccountData.username, trippin.PostData.posttext,
trippin.CategoryData.categoryname, Count(trippin.LikesDislikesData.liked)
as TimesLiked from trippin.PostData
inner join trippin.AccountData on trippin.PostData.accountid = trippin.AccountData.id
inner join trippin.CategoryData on trippin.CategoryData.id = trippin.PostData.categoryid
full outer join trippin.LikesDislikesData on trippin.LikesDislikesData.postid =
trippin.PostData.id
full outer join trippin.LikesDislikesData likes2 on trippin.LikesDislikesData.accountid =
trippin.AccountData.id
Group By (trippin.AccountData.username), (trippin.PostData.posttext), (trippin.categorydata.categoryname);
Here's my table setup (I've only included relevant columns):
LikesDislikesData
isliked(bit) || accountid(string) || postid(string
PostData
id(string) || posttext || accountid(string)
AccountData
id(string) || username(string)
CategoryData
categoryname(string)
Problem 1: FULL OUTER JOIN versus LEFT OUTER JOIN. Full outer joins are seldom what you want, it means you want all data specified on the "left" and all data specified on the "right", that are matched and unmatched. What you want is all the PostData on the "left" and any matching Likes data on the "right". If some right hand side rows don't match something on the left, then you don't care about it. Almost always work from left to right and join results that are relevant.
Problem 2: table alias. Where ever you alias a table name - such as Likes2 - then every instance of that table within the query needs to use that alias. Straight after you declare the alias Likes2, your join condition refers back to trippin.LikesDislikesData, which is the first instance of the table. Given the second one in joining on a different field I suspect that the postid and accountid are being matched on the same row, therefore it should be AND together, not a separate table instance. EDIT reading your schema closer, it seems this wouldn't be needed at all.
Problem 3: to solve you Counts problem separate them using CASE statements. Count will add the number of non NULL values returned for each CASE. If the likes.liked = 1, then return 1 otherwise return NULL. The NULL will be returned if the columns contains a 0 or a NULL.
SELECT trippin.PostData.Id, trippin.AccountData.username, trippin.PostData.posttext,
trippin.CategoryData.categoryname,
SUM(CASE WHEN likes.liked = 1 THEN 1 ELSE 0 END) as TimesLiked,
SUM(CASE WHEN likes.liked = 0 THEN 1 ELSE 0 END) as TimesDisLiked
FROM trippin.PostData
INNER JOIN trippin.AccountData ON trippin.PostData.accountid = trippin.AccountData.id
INNER JOIN trippin.CategoryData ON trippin.CategoryData.id = trippin.PostData.categoryid
LEFT OUTER JOIN trippin.LikesDislikesData likes ON likes.postid = trippin.PostData.id
-- remove AND likes.accountid = trippin.AccountData.id
GROUP BY trippin.PostData.Id, (trippin.AccountData.username), (trippin.PostData.posttext), (trippin.categorydata.categoryname);
Then "hide" the PostId column in the User Interface.
Instead of selecting Count(trippin.LikesDislikesData.liked) you could put in a select statement:
Select AccountData.username, PostData.posttext, CategoryData.categoryname,
(select Count(*)
from LikesDislikesData as likes2
where likes2.postid = postdata.id
and likes2.liked = 'like' ) as TimesLiked
from PostData
inner join AccountData on PostData.accountid = AccountData.id
inner join CategoryData on CategoryData.id = PostData.categoryid
USE AdventureWorksDW2008R2
GO
SET NOCOUNT ON
GO
/*
Default
*/
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
GO
BEGIN TRAN
IF OBJECT_ID('tempdb.dbo.#LikesDislikesData') IS NOT NULL
BEGIN
DROP TABLE #LikesDislikesData
END
CREATE TABLE #LikesDislikesData(
isLiked bit
,accountid VARCHAR(50)
,postid VARCHAR(50)
);
IF OBJECT_ID('tempdb.dbo.#PostData') IS NOT NULL
BEGIN
DROP TABLE #PostData
END
CREATE TABLE #PostData(
postid INT IDENTITY(1,1) NOT NULL
,accountid VARCHAR(50)
,posttext VARCHAR(50)
);
IF OBJECT_ID('tempdb.dbo.#AccountData') IS NOT NULL
BEGIN
DROP TABLE #AccountData
END
CREATE TABLE #AccountData(
accountid INT
,username VARCHAR(50)
);
IF OBJECT_ID('tempdb.dbo.#CategoryData') IS NOT NULL
BEGIN
DROP TABLE #CategoryData
END
CREATE TABLE #CategoryData(
categoryname VARCHAR(50)
);
INSERT INTO #AccountData VALUES ('1', 'user1')
INSERT INTO #PostData VALUES('1','this is a post')
INSERT INTO #LikesDislikesData (isLiked ,accountid, postid)
SELECT '1', P.accountid, P.postid
FROM #PostData P
WHERE P.posttext = 'this is a post'
SELECT *
FROM #PostData
SELECT *
FROM #LikesDislikesData
SELECT *
FROM #AccountData
SELECT COUNT(L.isLiked) 'Likes'
,P.posttext
,A.username
FROM #PostData P
JOIN #LikesDislikesData L
ON P.accountid = L.accountid
AND L.IsLiked = 1
JOIN #AccountData A
ON P.accountid = A.accountid
GROUP BY P.posttext, A.username
SELECT X.likes, Y.dislikes
FROM (
(SELECT COUNT(isliked)as 'likes', accountid
FROM #LikesDislikesData
WHERE isLiked = 1
GROUP BY accountid
) X
JOIN
(SELECT COUNT(isliked)as 'dislikes', accountid
FROM #LikesDislikesData
WHERE isLiked = 0
GROUP BY accountid) Y
ON x.accountid = y.accountid)
IF (XACT_STATE() = 1 AND ERROR_STATE() = 0)
BEGIN
COMMIT TRAN
END
ELSE IF (##TRANCOUNT > 0)
BEGIN
ROLLBACK TRAN
END
How do you think about the solution? We create a new table SummaryReport(PostID,AccountID,NumberOfLikedTime,NumberOfDislikedTimes).
An user clicks on LIKE or DISLIKE button we update the table. After that, you can query as you desire. Another advantage, the table can be served reporting purpose.

SQL: Want to alter the conditions on a join depending on values in table

I have a table called Member_Id which has a column in it called Member_ID_Type. The select statement below returns the value of another column, id_value from the same table. The join on the tables in the select statement is on the universal id column. There may be several entries in that table with this same universal id.
I want to adjust the select statement so that it will return the id_values for entries that have member_id_type equal to '7'. However if this is null then I want to return records that have member_id_type equal to '1'
So previously I had a condition on the join (commented out below) but that just returned records that had member_id_type equal to '7' and otherwise returned null.
I think I may have to use a case statement here but I'm not 100% sure how to use it in this scenario
SELECT TOP 1 cm.Contact_Relation_Gid,
mc.Universal_ID,
mi.ID_Value,
cm.First_Name,
cm.Last_Name,
cm.Middle_Name,
cm.Name_Suffix,
cm.Email_Address,
cm.Disability_Type_PKID,
cm.Race_Type_PKID,
cm.Citizenship_Type_PKID,
cm.Marital_Status_Type_PKID,
cm.Actual_SSN,
cm.Birth_Date,
cm.Gender,
mc.Person_Code,
mc.Relationship_Code,
mc.Member_Coverage_PKID,
sc.Subscriber_Coverage_PKID,
FROM Contact_Member cm (NOLOCK)
INNER JOIN Member_Coverage mc (NOLOCK)
ON cm.contact_relation_gid = mc.contact_relation_gid
AND mc.Record_Status = 'A'
INNER JOIN Subscriber_Coverage sc (NOLOCK)
ON mc.Subscriber_Coverage_PKID = sc.Subscriber_Coverage_PKID
AND mc.Record_Status = 'A'
LEFT outer JOIN Member_ID mi ON mi.Universal_ID = cm.Contact_Gid
--AND mi.Member_ID_Type_PKID='7'
WHERE cm.Contact_Relation_Gid = #Contact_Relation_Gid
AND cm.Record_Status = 'A'
Join them both, and use one if the other is not present:
select bt.name
, coalesce(eav1.value, eav2.value) as Value1OrValue2
from BaseTable bt
left join EavTable eav1
on eav1.id = bt.id
and eav1.type = 1
left join EavTable eav2
on eav2.id = bt.id
and eav2.type = 2
This query assumes that there is never more than one record with the same ID and Type.