condition in returning number of column - sql

I have table friends below.
-----------------------------
| id | user_id | friends_id |
-----------------------------
| 1 | 1 | 2 |
-----------------------------
| 2 | 1 | 3 |
-----------------------------
| 3 | 1 | 4 |
-----------------------------
| 4 | 2 | 1 |
-----------------------------
| 5 | 3 | 5 |
-----------------------------
| 6 | 4 | 5 |
-----------------------------
and SQL query:
select user_id, friends_id from friends where user_id = 1
Above query gives me below result.
------------------------
| user_id | friends_id |
------------------------
| 1 | 2 |
------------------------
| 1 | 3 |
------------------------
| 1 | 4 |
------------------------
I want to get resul like this:
------------------------
| user_id | friends_id |
------------------------
| 1 | many |
------------------------
If any user have friends more than 1, i must write word 'many'.
If any user have 1 friend, i must write his ID.
How i can do that?
I googled and can't explain to google my problem.

Do a GROUP BY to count number of friends. Use a CASE to return 'Many' if more than 1 friend, or the friend_id if only one (need to CAST to a character type, compatible with 'Many'.)
select user_id,
case when count(friends_id) > 1 then 'Many'
else cast(min(friends_id) as varchar(11)) end as friends_id
from friends
group by user_id

I update the query and include
SQL FIDDLE DEMO
WITH fCount as (
SELECT user_id, min(friends_id) friends_id, count(friends_id) nFriend
FROM friends
GROUP BY user_id
)
select user_id, CASE
WHEN nFriend > 1 THEN 'many'
ELSE cast(friends_id as nvarchar(10))
END friends_id
from fCount

try this
select user_id, CASE
WHEN count(friends_id) > 1 THEN 'many'
ELSE friends_id
END friends_id
from friends
where user_id = 1

Hi you can use below query:
CREATE TABLE #Temp (
ID INT Identity(1, 1)
,UID INT
,f_id NVARCHAR(10)
)
INSERT INTO #temp
SELECT 1
,2
UNION ALL
SELECT 1
,3
UNION ALL
SELECT 1
,4
UNION ALL
SELECT 2
,1
SELECT uid
,COUNT(f_id) AS COUNT_of_Friends
INTO #Temp2
FROM #temp
GROUP BY Uid
SELECT t1.Uid
,CASE
WHEN t2.COUNT_of_Friends > 1
THEN 'Many'
ELSE f_id
END AS F_id
FROM #temp T1
INNER JOIN #Temp2 T2 ON T1.Uid = t2.Uid

Related

Join number of pairs in a single table using SQL

I have two tables of events in bigquery that look like as follows. The main idea is two count the number of events in each table (are always pairs of event_id and user_id) and join them in a single table that for each pair in any table it tells the number of events.
table 1:
| event_id | user id |
| -------- | ------- |
| 1 | 1 |
| 2 | 1 |
| 2 | 3 |
| 2 | 5 |
| 1 | 1 |
| 4 | 7 |
table 2:
| event_id | user id |
| -------- | ------- |
| 1 | 1 |
| 3 | 1 |
| 2 | 3 |
I would like to get a table which has the number of events of each table:
| event_id | user id | num_events_table1 | num_events_table2 |
| -------- | ------- | ----------------- | ----------------- |
| 1 | 1 | 2 | 1 |
| 2 | 1 | 1 | 0 |
| 2 | 3 | 1 | 1 |
| 2 | 5 | 1 | 0 |
| 4 | 7 | 1 | 0 |
| 3 | 1 | 0 | 1 |
Any idea of how to do this with sql? I have tried this:
SELECT i1, e1, num_viewed, num_displayed FROM
(SELECT id as i1, event as e1, count(*) as num_viewed
FROM table_1
group by id, event) a
full outer JOIN (SELECT id as i2, event as e2, count(*) as num_displayed
FROM table_2
group by id, event) b
on a.i1 = b.i2 and a.e1 = b.e2
This is not getting exactly what I want. I amb getting i1 which are null and e1 that are null.
Consider below
#standardSQL
with `project.dataset.table1` as (
select 1 event_id, 1 user_id union all
select 2, 1 union all
select 2, 3 union all
select 2, 5 union all
select 1, 1 union all
select 4, 7
), `project.dataset.table2` as (
select 1 event_id, 1 user_id union all
select 3, 1 union all
select 2, 3
)
select event_id, user_id,
countif(source = 1) as num_events_table1,
countif(source = 2) as num_events_table2
from (
select 1 source, * from `project.dataset.table1`
union all
select 2, * from `project.dataset.table2`
)
group by event_id, user_id
if applied to sample data in your question - output is
If I understand correctly, the simplest method is to modify your query via a USING clause along with COALESCE():
SELECT id, event, COALESCE(num_viewed, 0), COALESCE(num_displayed, 0)
FROM (SELECT id, event, count(*) as num_viewed
FROM table_1
GROUP BY id, event
) t1 FULL JOIN
(SELECT id , event, COUNT(*) as num_displayed
FROM table_2
GROUP BY id, event
) t2
USING (id, event);
Note: This requires that the two columns used for the JOIN have the same name. If this is not the case, then you might still need column aliases in the subqueries.
One way is aggregate the union
select event_id, user id, sum(cnt1) cnt1, sum(cnt2) cnt2
from (
select event_id, user id, 1 cnt1, 0 cnt2
from table_1
union all
select event_id, user id, 0 cnt1, 1 cnt2
from table_2 ) t
group by event_id, user id

SQL query for finding records where count < 2

I have a table called Customer:
|device_id|user_id|
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 1 |
| 5 | 2 |
| 6 | 2 |
| 7 | 3 |
Now I want to return only the entries which have only 1 device per user. In this case only
|device_id|user_id|
| 7 | 3 |
Should be returned because user_id 3 is the only one with only 1 device (user_id 1 has 4, user_id 2 has 2)
How would I do that with a query?
One method is not exists:
select t.*
from t
where not exists (select 1
from t t2
where t2.user_id = t.user_id and t2.device_id <> t.device_id
);
You can also use aggregation:
select device_id, max(user_id) as user_id
from t
group by device_id
having count(*) = 1;
We can use group by to group the data on the basis of user_id followed by aggregate funciton to get the count of device:
SELECT device_id,user_id FROM customer where user_id IN
(
SELECT user_id from
(
SELECT user_id,count(*) FROM customer GROUP BY user_id HAVING count(*)<2
)
);

Select specific row but based on another column role

I tried and read many posts but I still can't figure out how to handle this request:
I have a table like below
+-------+---------------+------------+
| ID | Comp. | Role |
+-------+---------------+------------+
| 1 | abc | All |
+-------+---------------+------------+
| 1 | abc | Sales |
+-------+---------------+------------+
| 2 | def | All |
+-------+---------------+------------+
| 3 | zeh | All |
+-------+---------------+------------+
| 3 | zeh | TI |
+-------+---------------+------------+
I would like result role based, if one specific id have two role one is All and other is Sales then I need to consider Sales row
The output should be something like this
+-------+---------------+------------+
| ID | Comp. | Role |
+-------+---------------+------------+
| 1 | abc | Sales |
+-------+---------------+------------+
| 2 | def | All |
+-------+---------------+------------+
| 3 | zeh | TI |
+-------+---------------+------------+
UNION ALL will take the place
select * from table
where role <> 'All'
union all
select * from table t
where not exists (
select 1 from table
where id = t.id and [comp.] = t.[comp.] and role <> 'All'
)
order by 1
Result :
ID Comp. Role
1 abc Sales
2 def All
3 zeh IT
Hmmm . . . I think this does what you want:
select t.*
from t
where t.role = 'Sales'
union all
select t.*
from t
where t.role <> 'Sales' and
not exists (select 1 from t t2 where t2.id = t.id);
This will work if you have only 2 values for Role ('Sales' And 'All')
create table #tmp(ID INT,Comp VARCHAR(10),Role VARCHAR(10))
insert into #tmp
SELECT 1,'abc','All'
union ALL
SELECT 1,'abc','Sales'
union ALL
SELECT 2,'def','All'
select ID,Comp,MAX(Role) As Role from #tmp
Group by Id,comp
drop table #tmp
If you have other functions you should add then to the CASE WHEN
SELECT
ID
, Comp
, CASE WHEN role_id = 0 THEN 'All'
WHEN role_id = 1 THEN 'Sales'
WHEN role_id = 2 THEN 'TI'
ELSE NULL END AS Role
FROM
(
SELECT
ID
, Comp
, MAX(CASE WHEN Role = 'All' THEN 0
WHEN Role = 'Sales' THEN 1
WHEN Role = 'TI' THEN 2 END
ELSE -1 END) AS role_id
FROM
t
GROUP BY
ID
, Comp
)tmp
According to my understanding
SELECT ID,Comp,Role
FROM table1
WHERE ID IN(SELECT ID FROM table1 GROUP BY ID) AND Role != 'All'
UNION
SELECT ID,Comp,Role
FROM table1
WHERE ID IN(SELECT ID FROM table1 GROUP BY ID HAVING COUNT(ID)=1)
this is working fine check this demo

Convert tuple value to column names

Got something like:
+-------+------+-------+
| count | id | grade |
+-------+------+-------+
| 1 | 0 | A |
| 2 | 0 | B |
| 1 | 1 | F |
| 3 | 1 | D |
| 5 | 2 | B |
| 1 | 2 | C |
I need:
+-----+---+----+---+---+---+
| id | A | B | C | D | F |
+-----+---+----+---+---+---+
| 0 | 1 | 2 | 0 | 0 | 0 |
| 1 | 0 | 0 | 0 | 1 | 1 |
| 2 | 0 | 5 | 1 | 0 | 0 |
I don't know if I can even do this. I can group by id but how would you read the count value for each grade column?
CREATE TABLE #MyTable(_count INT,id INT , grade VARCHAR(10))
INSERT INTO #MyTable( _count ,id , grade )
SELECT 1,0,'A' UNION ALL
SELECT 2,0,'B' UNION ALL
SELECT 1,1,'F' UNION ALL
SELECT 3,1,'D' UNION ALL
SELECT 5,2,'B' UNION ALL
SELECT 1,2,'C'
SELECT *
FROM
(
SELECT _count ,id ,grade
FROM #MyTable
)A
PIVOT
(
MAX(_count) FOR grade IN ([A],[B],[C],[D],[F])
)P
You need a "pivot" table or "cross-tabulation". You can use a combination of aggregation and CASE statements, or, more elegantly the crosstab() function provided by the additional module tablefunc. All basics here:
PostgreSQL Crosstab Query
Since not all keys in grade have values, you need the 2-parameter form. Like this:
SELECT * FROM crosstab(
'SELECT id, grade, count FROM table ORDER BY 1,2'
, $$SELECT unnest('{A,B,C,D,F}'::text[])$$
) ct(id text, "A" int, "B" int, "C" int, "D" int, "F" int);

How to display same values in set of columns once sql

I have a sql query result like this
id | subId | code | name | response
1 | 1 | abc | xyz | "Whatever"
1 | 1 | abc | xyz | "Whatever2"
1 | 2 | def | qrt | "Whatever3"
1 | 2 | def | qrt | "Whatever4"
I need to show first four columns(id,subid,code,name) once(on the basis of id and subid) where as response ids and response values as it is like
id | subId | code | name | responsevalue
1 | 1 | abc | xyz | "Whatever"
| "Whatever2"
1 | 2 | def | qrt | "Whatever3"
| "Whatever4"
Use ROW_NUMBER() to get a row number of record in the group and then for all not first records (row number <> 1) output NULLs with CASE statement.
WITH T1 AS
(
SELECT T.*,
ROW_NUMBER() OVER (PARTITION BY ID ORDER BY responseid ) as rn
FROM T
)
SELECT
CASE WHEN rn=1 THEN ID ELSE NULL END as ID,
CASE WHEN rn=1 THEN SubId ELSE NULL END as SubID,
CASE WHEN rn=1 THEN Code ELSE NULL END as Code,
CASE WHEN rn=1 THEN Name ELSE NULL END as Name,
responseId,
response_value
FROM T1
ORDER BY T1.id,rn