How to add where condition if result count is greater than one - sql

I want to build SQL query that returns unique id.
My problem is that i need to add another condition to query if i have more than one result.
select u.id
from users u
where u.id in ('1','2','3')
and u.active = 'Y'
if i get more than one result i need to add:
and u.active_contact = 'Y'
I tried to build this query
select * from (
select u.id, count(u.id) as results
from users u
where u.id in ('1','2','3')
and u.active = 'Y'
group by u.id
) tab
If(tab.results > 1) then
where tab.u.active_contact = 'Y'
end
Thanks in advanced.
Hope i explained my self good enough.

Here's a different approach:
SELECT id
FROM (SELECT id, (CASE WHEN active ='Y' THEN 1 ELSE 0 END) + (CASE WHEN active_contact ='Y' THEN 1 ELSE 0 END) as actv FROM users ORDER BY actv DESC)
WHERE actv > 0
LIMIT 1
The subquery adds a column which aggregates active and active_contact. The main SELECT then optimizes the combination of these two fields, requiring at least one of them. I believe this provides the intended result.

Among the possible ways to solve this, here are two.
1) Use the active_contact id. If there is none use another id.
select coalesce( max(case when active_contact = 'Y' then id end), max(id) ) as id
from users
where id in ('1','2','3')
and active = 'Y';
2) Sort with active_contact coming first. Then get the first record.
select id
from
(
select id
from users
where id in ('1','2','3')
and active = 'Y'
order by case when active_contact = 'Y' then 1 else 2 end
) where rownum = 1;

A method using Analytic functions
SELECT id
FROM (SELECT u.id
, u.active_contact
, count(*) OVER () actives
FROM users u
WHERE u.id IN ('1','2','3')
AND u.active = 'Y')
WHERE ( actives = 1
OR ( actives > 1
AND active_contact = 'Y'))
If there is more than one record where active = 'Y' AND active_contact = 'Y' it will return them all. If only one of these is required you will need to identify the criteria for choosing that one.

Related

SQL using a function to check existence of event over a user id?

I have a table 'EVENTS' with a user column, and an 'event' column
User
Event
1
a
1
a
1
a
1
b
2
b
2
c
In the above example, user 1 has never had event c appear for them. I want to do something like
WITH table_a as (
SELECT
CASE WHEN EVENT = 'c' Then 'Y' ELSE 'n' end as event_occured,
user_id
FROM EVENTS)
and then get a result such as
User
is_occured
1
n
2
y
So I first tried to do it like such
SELECT DISTINCT USER,'y' is_occured FROM table_a WHERE event_occured='y'
UNION
SELECT DISTINCT USER,'n' is_occured FROM table_a WHERE event_occured='n'
But this is obviously a bit clunky, and will be unmanageable, especially as more columns are added to the event table, and needed in the query. so next I tried to do it using a window function, but I'm not certain how to pull the values into only singular users, where I'm only looking for the existence.
SELECT user,
CASE WHEN ... over(partion by user)
FROM EVENTS
But I'm very confused how to procede or if this is even the right track
If you are purely trying to get a Y or N onto these, you can do a simple MAX with a case expression:
select [User]
, MAX(case when [Event] = 'c' then 'Y' else 'N' end) is_occurred
from [EVENTS]
group by [User]
If you wanted to avoid group by, you could do a window function:
select distinct [User]
, MAX(case when [Event] = 'c' then 'Y' else 'N' end) over (partition by [User])
from [EVENTS]
If you wanted to have this as a function, you could parameterize the [Event] comparison and pass the user as well to something like:
select MAX(case when [Event] = #p_checked_event then 'Y' else 'N' end)
from [EVENTS]
where [User] = #p_checked_user
Return the results of that query, and call it like:
select distinct [User]
, CheckEventOccurred([User], 'c')
from [EVENTS]

Aggregate Function on an Expression Containing A Subquery

With the following t-sql query:
select u.userid
into #temp
from user u
where u.type = 1;
select top 50
contentid,
count(*) as all_views,
sum(case when hc.userid in (select userid from #temp) then 1 else 0 end) as first_count,
sum(case when hc.userid in (40615, 40616) then 1 else 0 end) as another_count
from hitcounts hc
inner join user u on u.userid = hc.userid
group by hc.contentid
order by count(*) desc;
I get an error message
Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
However, if just include the column 'another_count' (with the hard-coded list of identifiers), everything works as I expected. Is there a way I should go about only getting the count for userids contained within a subquery? I plan to have multiple columns, each counting up a set/subquery of different userids.
Performance is not a concern at this point and I appreciate any guidance.
You don't need a temporary table for this purpose. Just use a conditional aggregation:
select top 50 contentid,
count(*) as all_views,
sum(case when u.type = 1 then 1 else 0 end) as first_count,
sum(case when hc.userid in (40615, 40616) then 1 else 0 end) as another_count
from hitcounts hc join
user u
on u.userid = hc.userid
group by hc.contentid
order by count(*) desc;

Optimizing code with multple conditions on multiple tables?

I want to check whether these customers have LEAD action or SELL action which both stay in another tables. However, It takes like forever to finish it.
create table ct_nguyendang.visitor
as
select user_id, updated_at::date,
case
when user_id in (select distinct d_visitor_id from xiti.lead_detail) then 'lead'
else 'None'
end as lead_action,
case
when user_id in (select distinct account_id from ct_nguyendang.daily_listor) then 'sell'
else 'None'
end as sell_action
I think you can use union all and aggregation:
select user_id, max(is_lead) as has_lead, max(is_sale) as has_sale
from ((select d_visitor_id as user_id, 1 as is_lead, 0 as is_sale
from xiti.lead_detail
) union all
(select account_id, 0, 1
from ct_nguyendang.daily_listor
)
) ls
group by user_id;
If you have a table of users, then you can use correlated subqueries:
select u.*,
(case when exists (select 1
from xiti.lead_detail l
where u.user_id = l.d_visitor_id
)
then 1 else 0
end) as has_lead,
(case when exists (select 1
from ct_nguyendang.daily_listor s
where u.user_id = s.account_id
)
then 1 else 0
end) as has_sale
from users u;
Note that I prefer using 1 for "true" and 0 for "false". Of course, you can use string values if you prefer.
To optimize this query, you want indexes on xiti.lead_detail(d_visitor_id) and ct_nguyendang.daily_listor(account_id).

SQL Multiple Rows in Singleton Select

I have the following SQL:
WITH G1 AS
(SELECT G.NUM_REFE, G.GUIA AS MASTER,
(SELECT H.GUIA FROM SAAIO_GUIAS H WHERE G.NUM_REFE = H.NUM_REFE AND H.IDE_MH ="H" AND H.CONS_GUIA="1" ) AS HOUSE
FROM SAAIO_GUIAS G WHERE G.IDE_MH ="M" AND G.CONS_GUIA ="1" )
SELECT
*
FROM G1
And it returns the error
"Multiple Rows in Singleton Select".
This is a sample of the database
Any hint will be deeply appreciated
Thanks
Your query wants to retrieve the one matching GUIA, but it seems there can be multiple entries per NUM_REFE for IDE_MH = 'H' AND CONS_GUIA = 1. Check this with
select num_refe
from saaio_guias
where ide_mh = 'H'
and cons_guia = 1
group by num_refe
having count(*) > 1;
This should give no results, but it probably does. And if it does then it cannot work for your query and you must think about which value to pick in this case. Maybe simply the minimum or maximum:
(
select min(h.guia)
from saaio_guias h
...
Or maybe you want to delete rows from the table that you consider duplicates and add a constraint (unique index on num_refe + ide_mh + cons_guia) to prevent from such records in the future.
Your query can be written simpler using conditional aggregation by the way:
select
num_refe,
any_value(case when ide_mh = 'M' then guia end) as master,
any_value(case when ide_mh = 'H' then guia end) as guia
from saaio_guias
where cons_guia = 1
group by num_refe
order by num_refe;
Thie problem is in CTE SELECT Subquery.
I think you can use CASE express instead of SELECT Subquery
WITH G1 AS
(
select
num_refe,
Case when ide_mh = 'M' then GUIA ELSE '' END as MASTER,
Case when ide_mh = 'H' then GUIA ELSE '' END as HOUSE
from saaio_guias
where cons_guia = 1
)
SELECT
*
FROM G1
OR
SELECT G.NUM_REFE, G.GUIA AS MASTER,H.GUIA
FROM SAAIO_GUIAS G
INNER JOIN
(
SELECT *
FROM SAAIO_GUIAS
WHERE IDE_MH ='H' AND CONS_GUIA='1'
) AS H ON G.NUM_REFE = H.NUM_REFE
WHERE G.IDE_MH ='M' AND G.CONS_GUIA ='1'
I don't know what is your expect result.So I guess these two query might help you.

counting number of times a particular level and then aggregating it the number of times in new variable

Counting number of times a particular level (in transaction data) and then aggregating it the number of times in new variable (under one row per customer)
I have 2 levels to solicitation method, phone and email. I have created 2 new columns which count the number of times phone or email happened per id. Right now I have transaction data and cant figure out how to go about it. the data is on left, what I want is on right. I am okay with both kinds of output on right side.
So far I tried this. returns error
create table d.email as
select ID, email_count
from d.emai
where email_count = (select count (*)
from d.email
group by ID
having SolicitMethod = 'Email' );
quit;
I am not sure what you really want to do, but you can fix the syntax error by making the subquery a correlated subquery:
create table d.email as
select ID, email_count
from d.emai e
where email_count = (select count(*)
from d.email e2
where e2.SolicitMethod = 'Email' and e2.id = e.id
);
I assume the reference in the first from should be d.emai.
The first output can be obtain with this query:
It groups rows by id, and then count how many rows are on each SolicitMethod
SELECT id
, SUM(CASE
WHEN SolicitMethod = 'Email' THEN 1
ELSE 0
END) count_email
, SUM(CASE
WHEN SolicitMethod = 'phone' THEN 1
ELSE 0
END) count_phone
FROM d.email
GROUP BY id
This second output query depends of your dbms and availability of analytics function:
it count on each rows the count of sollicitMethod of each group of id
SELECT id
, SUM(CASE
WHEN SolicitMethod = 'Email' THEN 1
ELSE 0
END)
OVER (partition BY id) count_email
, SUM(CASE
WHEN SolicitMethod = 'phone' THEN 1
ELSE 0
END)
OVER (partition BY id) count_phone
FROM d.email