Insert case when into table from joined table - sql

I'm new to SQL and I'm having some trouble solving a problem. I'm rewriting a script where I can match with customers who have received an email. Previously I have been using session tables as below:
DECLARE GLOBAL TEMPORARY TABLE EMAIL_SENDS
(
ACCOUNT_NUMBER INT
)
WITH REPLACE
ON COMMIT PRESERVE ROWS
;
INSERT INTO SESSION.EMAIL_SENDS
SELECT ACCOUNT_NUMBER
FROM SENT_DATA A
JOIN MAIN_TABLE B
ON A.CLIENT_ID_SUBKEY = B.CUST_ID
OR A.CLIENT_ID_SUBKEY = B.OLD_ID
WHERE SEND_ID = 123456
GROUP BY ACCOUNT_NUMBER
;
Then when pulling the data I have just used CASE WHEN C.ACCOUNT_NUMBER IS NOT NULL THEN 1 ELSE 0 END joining the MAIN_TABLE with the EMAIL_SENDS to flag who has and hasn't received the email.
However I would like to improve the process, and add a column to the MAIN_TABLE stating who has received an email and who hasn't.
This is my script so far:
ALTER TABLE MAIN_TABLE
ADD EMAILED INT
;
INSERT INTO MAIN_TABLE
SELECT EMAILED
CASE WHEN ACCOUNT_NUMBER IS NOT NULL THEN 1 ELSE 0 END
FROM (SENT_DATA A
JOIN MAIN_TABLE B
ON A.CLIENT_ID_SUBKEY = B.CUST_ID
OR A.CLIENT_ID_SUBKEY = B.OLD_ID
WHERE SEND_ID = 123456
GROUP BY ACCOUNT_NUMBER
)
;
As I'm new to SQL I'm not able to figure out where I'm going wrong (even though it's probably obvious to anyone proficient at it).

try this. replace column names from main table to with this (EMAILED,ACCOUNT_NUMBER)
INSERT INTO MAIN_TABLE (EMAILED,ACCOUNT_NUMBER)
SELECT EMAILED,
CASE WHEN ACCOUNT_NUMBER IS NOT NULL THEN 1 ELSE 0 END
FROM (SENT_DATA A
JOIN MAIN_TABLE B
ON A.CLIENT_ID_SUBKEY = B.CUST_ID
OR A.CLIENT_ID_SUBKEY = B.OLD_ID
WHERE SEND_ID = 123456
GROUP BY ACCOUNT_NUMBER
)
;

Related

SQL Oracle - CASE WHEN for separately ID's [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I have some (thousands ;)) ID's and I'm trying check their relationship separately. But I have problem with checking relationship for each ID independently. Actualy my code check this for all ID`s beetwen them..
Table for example
ID Service
1 A
1 A1
2 A
2 B
3 A
3 A1
SQL code
SELECT a.ID, a.service,
CASE
WHEN a.service IN ('A','A1') THEN 'Yes'
ELSE 'No'
END
FROM t1 a
Output
ID Service RELATION
1 A YES
1 A1 YES
2 A NO
2 B NO
3 A YES
3 A1 YES
First, you should sort your table according to service alphabetically.
Then create an array and populate it with all the services:
DECLARE
CURSOR c_t1 is
SELECT service FROM t1;
type c_list is varray (6) of t1.service%type;
service_list c_list := c_list();
counter integer :=0;
BEGIN
FOR n IN c_t1 LOOP
counter := counter + 1;
service_list.extend;
service_list(counter) := n.service;
dbms_output.put_line('Service('||counter ||'):'||service_list(counter));
END LOOP;
END;
/
Then iterate through your table values:
DECLARE
v_count number DEFAULT 0;
BEGIN
FOR i IN (SELECT t1.ID, t1.service FROM t1)
LOOP
FOR j IN (service_list.COUNT)
LOOP
CASE
WHEN t1.service IN (service_list[i], service_list[i+1]) THEN 'Yes'
ELSE 'No'
END
v_COUNT := v_COUNT + 1;
END LOOP;
END LOOP;
DBMS_OUTPUT.PUT_LINE(v_COUNT);
END;
/
The following query works though I'm not sure how it would perform.
WITH a1
AS (SELECT id, 1 AS here
FROM services
WHERE service = 'A1')
, a
AS (SELECT id, 1 AS here
FROM services
WHERE service = 'A')
SELECT driver.id
, driver.service
, CASE
WHEN NVL(a1.here, 0) + NVL(a.here, 0) > 1 THEN 'YES'
ELSE 'NO'
END
FROM services driver
LEFT OUTER JOIN a1 ON a1.id = driver.id
LEFT OUTER JOIN a ON a.id = driver.id
But I have problem with checking relationship for each ID
independently
That is why it is suggested to you to create a new table storing all the unique relationships between the services. This gives you a better handle to compare the relations and give you the desired output.
You should start by creating the relationship table which stores values like this.
|rid| S1 | S2 |
--- |----|----|
|1 | A | A1 |
Now, to generate your desired output, you should first use a self join to get the pairs of relations with common IDs .
SELECT a.id,
a.service,
b.service
FROM t1 a
join t1 b
ON ( a.service != b.service
AND a.id = b.id ) ;
Once you have got such combinations, all you would need is to check if that combination of relation exists using an OUTER JOIN with relationship table, which will help you to get the output as "YES" or "NO" based on the existence.
SELECT a.id,
b.service,
CASE
WHEN r.id IS NULL THEN 'NO'
ELSE 'YES'
END AS relation
FROM t1 a
join t1 b
ON ( a.service != b.service
AND a.id = b.id )
left join rel r
ON ( ( r.s1 = a.service
AND r.s2 = b.service )
OR ( r.s2 = a.service
AND r.s1 = b.service ) );
Demo
I would use window function :
select t1.*, (case when sum(case when service not in ('A', 'A1') then 1 else 0 end) over (partition by id) = 0
then 'yes' else 'no'
end) as Relation
from t1;
this will work and you have to use decode function for it:
create table ex2(
no1 number,
no2 varchar(20));
insert into ex2 values(1, 'A');
insert into ex2 values(1 , 'A1');
insert into ex2 values(2 , 'A');
insert into ex2 values(2 , 'B');
insert into ex2 values(3 , 'A');
insert into ex2 values(3 , 'A1');
select * from ex2;
SELECT no1, no2 ,
decode(no2,'A','yes','A1','yes','no')
FROM ex2;
output:
1 A yes
2 A yes
2 B no
3 A yes
3 A1 yes
1 A1 yes
for your table query is :
SELECT ID, service ,
decode(service,'A','yes','A1','yes','no')
FROM ex2;

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.

Adding new column (with inner join) and insert (update) value with case when (SQL Server 2012)

What is the best approach to add a column to an existing table with values
I've the following tables:
Table_A
ClientID, StatementID, CustBuy
Table_B
NewClientID
I want to add a new column YTD_Jan13
alter Table_A add YTD_Jan13 varchar(20)
select
(case
when CustBuy=0 and StatementID>='01.01.2013' then 'New YTD'
else 'Repead YTD'
end) as YTD_Jan13
from A inner join B
on A.ClientID = B.NewClientID
Basically I want to insert value in a new column (YTD_Jan13) with following conditions:
If
1) Table_A.ClientID = Table_B.NewClientID
2) in a Table_A (CustBuy=0 and StatementID>='01.01.2013') then 'New YTD'
else 'Repead YTD'
I'm confused, I'm asking for your help
Thanks in advance
BR, Habib
alter Table_A add YTD_Jan13 varchar(20)
Then stick your 'else' value in
update Table_A Set YTD_Jan13 = 'Repeat YTD'
then (this is called an update with join)
UPDATE a
SET a.YTD_Jan13 = 'New YTD'
FROM Table_A a
INNER JOIN B
ON A.ClientID = B.ClientID
Where CustBuy = 0 and StatementID >= '01.01.2013'
NB There is an assumption that there are no records for clients in A that are not in B. If there are you'll have to get a bit cleverer so YTD_Jan13 would be left null in those cases.

SQL find difference between two table

I need to compare email record (by email address) between two tables (Table A as Production data and B as old data) to find the difference and show the result in column such as "New", "Delete" and etc.
If exists in Table A, not in Table B, it should mark "New"
else if exists in Table B, not in Table A, it should mark "Delete"
if appears in both table, it should mark "Maintain"
I want the result like that
DisplayName LastName Diremail Result
==============================================
XXX XXX a#a.com New
ABC ABC 1#a.com Delete
DDD DDD 2#a.com Maintain
My code as follows:
SELECT b.DisplayName,
b.LastName,
b.diremail,
Result = CASE WHEN a.DirEmail IS NULL THEN 'New'
when b.DirEmail IS null then 'delete'
else 'Maintain'
END
FROM vHRIS_StaffDB b
LEFT JOIN HRIS_DL_Lists a
ON a.DirEmail = b.DirEmail
WHERE (
a.DirEmail IS NULL
OR a.DisplayName != b.DisplayName
)
but the data not correct as the code not return record which should "Delete"
(found in table b, not in table a)
pls advise. Thanks.
Sounds like you need full join instead of left join. Try this:
SELECT coalesce(b.DisplayName, a.DisplayName) DisplayName,
coalesce(b.LastName, a.LastName) LastName,
coalesce(b.diremail, a.diremail) diremail,
Result = CASE WHEN a.DirEmail IS NULL THEN 'New'
when b.DirEmail IS null then 'delete'
else 'Maintain'
END
FROM vHRIS_StaffDB b
FULL JOIN HRIS_DL_Lists a
ON a.DirEmail = b.DirEmail
WHERE (
a.DirEmail IS NULL
OR a.DisplayName != b.DisplayName
)

update table where there is duplicate records using sql

i am trying to update a table but my problem is the target table has duplicate records so my update is failing for that reason. This is the error: attempt to update a target row with values from multiple join rows. I know when updating a table, we have to join unique keys but i cannot delete the duplicates from the table so i am looking for a work around for my situation. The CUSTOMERTABLE is the one that has the duplicates. Here is my query:
UPDATE CUSTOMERTABLE
SET SERVICE = 'BILLING'
FROM
(SELECT distinct(CUSTOMER_ID)AS ACCT_ID
,ED.CUSTOMER_NAME
, ED.CUSTOMER_ADDRESS
FROM CUSTOMER_RELATION ED, STG_CUSTOMER_REV TXN
WHERE ED.CUSTOMER_ID = TXN.CUS_ID
)AS X
WHERE X.ACCT_ID = CUSTOMERTABLE.ACCOUNT_NUMBER;
Try writing it with an IN clause:
UPDATE CUSTOMERTABLE
SET SERVICE = 'BILLING'
WHERE CUSTOMERTABLE.ACCOUNT_NUMBER IN
(SELECT CUSTOMER_ID
FROM CUSTOMER_RELATION ED
JOIN STG_CUSTOMER_REV TXN ON ED.CUSTOMER_ID = TXN.CUS_ID)
Here is another option, which probably has a better performance compared to an IN solution if CUSTOMER_RELATION or STG_CUSTOMER_REV are large tables.
UPDATE C
SET SERVICE = 'BILLING'
FROM CUSTOMERTABLE C
WHERE EXISTS (SELECT 1
FROM CUSTOMER_RELATION ED, STG_CUSTOMER_REV TXN
WHERE ED.CUSTOMER_ID = TXN.CUS_ID AND CUSTOMER_ID = C.ACCOUNT_NUMBER);
Try grouping on the CustomerId
UPDATE CUSTOMERTABLE
SET SERVICE = 'BILLING'
FROM
(SELECT distinct(CUSTOMER_ID)AS ACCT_ID
,ED.CUSTOMER_NAME
, ED.CUSTOMER_ADDRESS
FROM CUSTOMER_RELATION ED, STG_CUSTOMER_REV TXN
WHERE ED.CUSTOMER_ID = TXN.CUS_ID
GROUP BY ED.CUSTOMER_ID
)AS X
WHERE X.ACCT_ID = CUSTOMERTABLE.ACCOUNT_NUMBER;
You need to make sure that your select return non duplicates. Try using that select without the update statement and check if the select cotains the duplicates you want to get rid off.