Enriching Table - sql

This is my query:
SELECT
a.account_type AS ACCOUNT_TYPE
,b.at_account_type_desc
,COUNT(a.BAN) AS num_BAN
FROM csm_adx.billing_account_act AS a
LEFT OUTER JOIN csm_adx.account_type_act AS b ON a.account_type = b.at_acc_type
GROUP BY 1,2
Now I want to connect it to another table TABLE_C which contains the information is the account: tentative, cancelled, closed, suspended, open.
I would like my result table to contain aditional three columns: ACTIVE_BAN, SUSPENDED_BAN and CANCELLED_BAN
and that each value contains the number of current active, suspended and cancelled bans. I´m using Teradata.
Can you please help me do this?
This is the result when the table is connected with another table which contains BAN status:
SELECT
a.account_type AS ACCOUNT_TYPE
,b.at_account_type_desc
,c.description
,COUNT(a.BAN) AS num_BAN
FROM csm_adx.billing_account_act AS a
LEFT OUTER JOIN csm_adx.account_type_act AS b
ON a.account_type = b.at_acc_type
LEFT OUTER JOIN csm_adx.acct_status AS c
ON a.ban_status = c.original_status_code
GROUP BY 1,2,3

SELECT
a.account_type AS ACCOUNT_TYPE
,b.at_account_type_desc
,COUNT(a.BAN) AS num_BAN ,
sum(case when a.column=value then 1 else 0 end) as 'user_colname1',
sum(case when b.column=value then 1 else 0 end) as 'user_colname2'
FROM csm_adx.billing_account_act AS a
LEFT OUTER JOIN csm_adx.account_type_act AS b
ON a.account_type = b.at_acc_type
GROUP BY 1,2

Related

JOIN AND CASE MORE AN TABLE

I have 2 tables; the first one ORG contains the following columns:
ORG_REF, ARB_REF, NAME, LEVEL, START_DATE
and the second one WORK contains these columns:
ARB_REF, WORK_STREET - WORK_NUM, WORK_ZIP
I want to do the following: write a select query that search in work and see if the WORK_STREET, WORK_ZIP are duplicate together, then you should look at WORK_NUM. If it is the same then output value ' ok ', but if WORK_NUM is not the same, output 'not ok'
I wrote this SQL query:
select
A.ARB_REF, A.WORK_STREET, A.WORK_NUM, A.WORK_ZIP
case when B.B = 1 then 'OK' else 'not ok' end
from
work A
join
(select
WORK_STREET, WORK_ZIP count(distinct , A.WORK_NUM) B
from
WORK
group by
WORK_STREET, WORK_ZIP) B on B.WORK_STREET = A.WORK_STREET
and B.WORK_ZIP = A.WORK_ZIP
Now I want to join the table ORG with this result I want to check if every address belong to org if it belong I should create a new column result and set it to yes in it (RESULT) AND show the "name" column otherwise set no in 'RESULT'.
Can anyone help me please?
While you can accomplish your result by adding a left outer join to the query you've already started, it might be easiest to just use count() over....
with org_data as (
-- do the inner join before the left join later
select * from org1 o1 inner join org2 o2 on o2.orgid = o1.orgid
)
select
*,
count(*) over (partition by WORK_STREET, WORKZIP) as cnt,
case when o.ARB_REF is not null then 'Yes' else 'No' end as result
from
WORK w left outer join org_data o on o.ARB_REF = w.ARB_REF

Adding CASE expression in the correct spot?

I want to change this query:
select
t.AccountA
,t.AccountB
,t.totalNumber
,a.Category
from TableA t
left join Accounts a
on t.ActNum = a.ActNum
left join
(select distinct
s.col1
from (
select ....
from Table
group by...
) st
left join (select S....
group by..
) g on...
left join (select... on ...
) t on ...
where...
)
so that c.AccountB displays "X" if it was a "Y". So I want to do something like
CASE WHEN c.AccountB = 'Y' THEN 'X' ELSE 'c.AccountB END
Except I'm having a problem where some data (a.Category) is coming from the table a, and table a doesn't have a record in it equal to "Y", so the join doesn't get the category data from a. That field is therefore blank. I'm trying to avoid adding it to that table and would rather change the query. How can I do this? What I think would work is:
select
t.AccountA
,t.AccountB
,t.totalNumber
,a.Category
from TableA t
left join ****** (Select CASE WHEN t.AccountB = 'Y' THEN 'X' ELSE 't.AccountB END Accounts a)
on t.ActNum = a.ActNum
left join
(select distinct
col1
from (
select ....
from Table
group by...
) sta
left join (select S....
group by..
) g on...
left join (select... on ...
) t on ...
where...
)
Where I put the CASE expression in the 7th line here by the asterisks ***
Will this return exactly the same records? This is a really long running query and difficult to test so I'm trying to run it as few times as possible, would like some input to help me so this doesn't turn into a 6 hour project.
EDIT: I had a typo, the first columns selected were supposed to reference the first table - I changed it (table "t")
First, this might be as simple as getting rid of the single quote before c.AccountB CASE WHEN c.AccountB = 'Y' THEN 'X' ELSE c.AccountB END Otherwise I'm not quite sure I understand what you want but I'll try:
If you just want to select then:
select
c.AccountA
,CASE WHEN c.AccountB = 'Y' THEN 'X' ELSE c.AccountB END AccountB
,totalNumber
,a.Category
from TableA t
left join Accounts a
on t.ActNum = a.ActNum
left join
...
If instead you want to use this as part of a join you'll have to use it in your join. Since you don't show how "c" is joined, nor how "c" and "a" are related I will try to give an example:
select
c.AccountA
,CASE WHEN c.AccountB = 'Y' THEN 'X' ELSE c.AccountB END AccountB
,totalNumber
,a.Category
from CheckRegister c
left join Accounts a
on a.ActNum = c.AccountA
left join Accounts b
on b.ActNum = CASE WHEN c.AccountB = 'Y' THEN 'X' ELSE c.AccountB END

Outer join with mandatory chain

Imagine I have this data
people -> address changes -> address change reasons
I want details of all people
I also want to know if they have ever changed address because of fire. So I don't want to know what the reasons are but if they have changed address for 1 single reason.
Each person could possibly have multiple address change reasons
so I have
SELECT people.*
CASE WHEN add_change.reason_id is not NULL THEN
'Y'
ELSE
'N'
END as been_fire
from people
left outer join add_change ON person.id = add_change.person
left outer join add_change_reason ON add_change.reason_id = add_change_reason.id AND add_change_reason.text = 'FIRE'
but this returns multiple rows per person if they have many address changes.
I can't just use
left outer join add_change ON add_change.person = person.id AND add_change.reason_id = 5
as this isn't fixed data.
Use exists:
SELECT p.*,
(CASE WHEN EXISTS (SELECT 1
FROM add_change ac JOIN
add_change_reason acr
ON ac.reason_id = acr.id
NVL(address_change.reason,'N')
WHERE p.id = ac.person AND
acr.text = 'FIRE'
)
THEN 'Y' ELSE 'N'
END) as has_fire_address_change
from people p;
Note that this changes the flag to 'Y' and 'N', which is what the description of your problem suggests that you want.
You could do a left join to a derived table that only returns person IDs that do have the change reason 'FIRE':
SELECT p.*
CASE WHEN cr.person IS NOT NULL THEN 'Y' ELSE 'N' END as been_fire
from people
left join (
select ac.person
from add_change ac
where exists (select *
from add_change_reason acr
where acr.id = ac.reason_id
AND acr.text = 'FIRE')
) cr on cr.person = p.id

Create overview table with true false values based on rows exist in child table

I have a table with cases, and another table with notifications.
For simplicity let's say the case table contains
id int
name nvarchar(100)
The notification table contains:
id int
caseid int
notificationtype string
Notification types can be either 'standard' or 'critical'.
I'd like an sql that can give me an overview for each case, and if they have any critical or standard notifications.
So a result like this:
CaseId CaseName StdNotification CriticalNotification
1 Test case yes no
I tried this SQL:
select distinct case.id as CaseId,
case.name as CaseName,
notifications.notificationtype,
case notifications when 'standard' then 'yes' else 'no' end as StdNotification,
case notifications when 'critical' then 'yes' else 'no' end as CriticalNotification
from cases
inner join notifications on Notifications.caseid = case.id
But this gives me duplicate rows for each combination
CaseId CaseName StdNotification CriticalNotification
1 Test case yes no
1 Test case no yes
So, how do I construct a sql that wil make some kind of "sum" and only return one row for each case?
You don't want distinct. You want group by. Your data structure suggests that a given case could have more than one notification, so I would go with counts using conditional aggregation:
select c.id as CaseId, c.name as CaseName,
sum(case when n.notificationtype = 'Standard' then 1 else 0 end) as NumStandard,
sum(case when n.notificationtype = 'Critical' then 1 else 0 end) as numCritical
from cases c left join
notifications n
on n.caseid = c.id
group by c.id, c.name;
You can convert these to "yes" and "no" using another case.
Also, note that I changed the inner join to a left join, so you'll get cases that have no notifications at all.
SELECT C.id as CaseId,
C.name as CaseName,
IIF(n1.notificationtype IS null, 'no', 'yes') as StdNotification,
IIF(n2.notificationtype IS null, 'no', 'yes') as CriticalNotification
FROM [case] C
left join notification n1
on C.id = n1.caseid and n1.notificationtype = 'standard'
left join notification n2
on C.id = n2.caseid and n2.notificationtype = 'critical'

incorrect joins - 1 row per result set

I trying to determine which people in my databases have either unsubscribed from my news letters, which people have bad email addresses and which dont have either. I have activities activities for both iUnsub' and 'iBadEmail'.
the code i wrote was
select distinct
n.id,
'Unsubscribe' =
case
when a.activity_type = 'iUnsub' then '1'
end,
'Bad Email' =
case
when a.activity_type = 'iBadEmail' then '1'
end
from name n
left join activity a on n.id = a.id
where n.id in
(
'1002421',
'1005587',
'1009073',
'1001102'
)
the results i receive creates 2 results for each id
id Unsubscribe Bad Email
1001102 NULL NULL
1002421 NULL NULL
1002421 1 NULL
1005587 NULL NULL
1005587 1 NULL
1009073 NULL 1
1009073 NULL NULL
i would like to the code to only give me one row for each id like below
id Unsubscribe Bad Email
1001102 NULL NULL
1002421 1 NULL
1005587 1 NULL
1009073 NULL 1
The problem is that you have multiple activity rows 3 or your names, and you are returning a row in the result for each activity. Name 1001102 either has no or only one activity which is neither Unsub or BadEmail.
select n.Id,
sum(case when a.activity_id = 'iUnSub' then 1 else 0 end) UnSub,
sum(case when a.activity_id = 'iBadEmail' then 1 else 0 end) BadEmail
from name
left outer join activity a on n.id = a.id
where a.activity
and n.id in
(
'1002421',
'1005587',
'1009073',
'1001102'
)
group by n.Id
This will give you a non-zero figure if UnSubbed or BadEmail, and if both are 0, then it's presumably OK.
The left outer join is for cases whene a name has no activity rows. If you don't include that then they will not be included in the output. If that's fine, change it to an inner join.