how to find out the duplicates and count them in another table - sql

i have an sqlite table like Results and want to make a table like finalResults by counting the number of options. i am using sqlite
Table Name: Results Table Name: finalResults
___________ _________ __________ _______ ________ _______ _______
questionId| optionId questionId| option1 | option2 |option3 |option4
-------------------- -----------------------------------------------
40 | 3 40 | 1 | 2 | 4 | 1
40 | 3 41 | 2 | 1 | 1 | 3
40 | 2
40 | 4
40 | 2
40 | 1
40 | 3
40 | 3
41 | 1
41 | 3
41 | 2
41 | 4
41 | 4
41 | 4
41 | 1
Thank you

You can do it like this
INSERT INTO finalResults(questionId, option1, option2, option3, option4)
SELECT questionId,
MIN(CASE WHEN optionid = 1 THEN n END) option1,
MIN(CASE WHEN optionid = 2 THEN n END) option2,
MIN(CASE WHEN optionid = 3 THEN n END) option3,
MIN(CASE WHEN optionid = 4 THEN n END) option4
FROM
(
SELECT questionId, optionid, COUNT(*) n
FROM results
GROUP BY questionId, optionid
) q
GROUP BY questionId
Here is SQLFiddle demo
or
INSERT INTO finalResults(questionId, option1, option2, option3, option4)
SELECT questionId,
SUM(CASE WHEN optionid = 1 THEN 1 ELSE 0 END) option1,
SUM(CASE WHEN optionid = 2 THEN 1 ELSE 0 END) option2,
SUM(CASE WHEN optionid = 3 THEN 1 ELSE 0 END) option3,
SUM(CASE WHEN optionid = 4 THEN 1 ELSE 0 END) option4
FROM results
GROUP BY questionId
Here is SQLFiddle demo
Output in both cases:
| questionId | option1 | option2 | option3 | option4 |
------------------------------------------------------
| 40 | 1 | 2 | 4 | 1 |
| 41 | 2 | 1 | 1 | 3 |

try following query
select questionId,
sum(optionId==1) as option1,
sum(optionId==2) as option2,
sum(optionId==3) as option3
from results
group by questionId
or sqlfiddle http://sqlfiddle.com/#!7/415b7/6 (open into chrome & safari)

Related

How to know arithmetic mean of two count values

I have table answers where I store information.
| EMPLOYEE | QUESTION_ID | QUESTION_TEXT | SELECTED_OPTION_ID | SELECTED_OPTION_TEXT |
|----------|-------------|------------------------|--------------------|----------------------|
| Mark | 1 | Do you like soup? | 1 | Yes |
| Kate | 1 | Do you like soup? | 1 | Yes |
| Jone | 1 | Do you like soup? | 2 | No |
| Kim | 1 | Do you like soup? | 3 | I don't know |
| Alex | 1 | Do you like soup? | 2 | No |
| Bond | 1 | Do you like soup? | 1 | Yes |
| Ford | 1 | Do you like soup? | 3 | I don't know |
| Mark | 2 | Do you like ice cream? | 2 | No |
| Kate | 2 | Do you like ice cream? | 1 | Yes |
| Jone | 2 | Do you like ice cream? | 1 | Yes |
| Kim | 2 | Do you like ice cream? | 1 | Yes |
| Alex | 2 | Do you like ice cream? | 2 | No |
| Bond | 2 | Do you like ice cream? | 1 | Yes |
| Ford | 2 | Do you like ice cream? | 3 | I don't know |
Formulas:
value_1 = (Number of users who answered "No" or "I don't know" to the first question) / (The total number of people who answered to the first question)
value_2 = (Number of users who answered "No" or "I don't know" to the second question) / (The total number of people who answered to the first question)
I can separately find the values according to the above formulas. For example value_1:
select
count(*)
from
answers
where
question_id = 1
and (
selected_option_id in (2, 3)
or
selected_option_text in ('No', 'I don\'t know')
)
My question is how to arithmetic mean of these 2 values correctly by one sql query?
In other words I need to find average value:
You could use a condition sum
select (sum( case when QUESTION_ID = 1 AND
SELECTED_OPTION_ID in ( 2,3) THEN 1 else 0 end )::float /
sum( case when QUESTION_ID = 1 then 1 else 0 end)::float )*100 first_question_rate,
(sum( case when QUESTION_ID = 2 AND
SELECTED_OPTION_ID in ( 2,3) THEN 1 else 0 end )::float /
sum( case when QUESTION_ID = 2 then 1 else 0 end)::float)*100 second_question_rate,
(( sum( case when QUESTION_ID = 1 AND SELECTED_OPTION_ID in ( 2,3) THEN 1 else 0 end )::float /
sum( case when QUESTION_ID = 1 then 1 else 0 end)::float +
sum( case when QUESTION_ID = 2 AND SELECTED_OPTION_ID in ( 2,3) THEN 1 else 0 end )::float /
sum( case when QUESTION_ID = 2 then 1 else 0 end) ::float)/2)*100 avg
from answer
Are you looking for something like below-
SELECT
SUM(CASE WHEN QUESTION_ID = 1 AND SELECTED_OPTION_TEXT <> 'Yes' THEN 1 ELSE 0 END)
/
SUM(CASE WHEN QUESTION_ID = 1 THEN 1 ELSE 0 END) value_1 ,
SUM(CASE WHEN QUESTION_ID = 2 AND SELECTED_OPTION_TEXT <> 'Yes' THEN 1 ELSE 0 END)
/
SUM(CASE WHEN QUESTION_ID = 2 THEN 1 ELSE 0 END) value_2
FROM answers
For getting average, please use the below script-
SELECT (A.value_1+A.value_2)/2.0
FROM
(
SELECT
SUM(CASE WHEN QUESTION_ID = 1 AND SELECTED_OPTION_TEXT <> 'Yes' THEN 1 ELSE 0 END)*1.0
/
SUM(CASE WHEN QUESTION_ID = 1 THEN 1 ELSE 0 END)*1.0 value_1 ,
SUM(CASE WHEN QUESTION_ID = 2 AND SELECTED_OPTION_TEXT <> 'Yes' THEN 1 ELSE 0 END)*1.0
/
SUM(CASE WHEN QUESTION_ID = 2 THEN 1 ELSE 0 END)*1.0 value_2
FROM answers
)A
I'm pretty sure you want conditional aggregation. I suspect you want:
select question_id,
count(*) filter (where selected_option_id in (2, 3)) as num_2_3,
avg( selected_option_id in (2, 3)::int ) as ratio_2_3
from answers
group by question_id;
For each question, this provides the number of answers that are 2 or 3 and the ratio of those answers to all answers.

Select specific columns by their alias, and later order by it

My table are the following
+----+----------+--------+
| id | priority | User |
+----+----------+--------+
| 1 | 2 | [null] |
| 2 | 1 | [null] |
| 3 | 3 | Tony |
| 4 | 2 | John |
| 5 | 2 | Andy |
| 6 | 1 | Mike |
+----+----------+--------+
My goal is to extract them, and order by the following combined conditions:
priority = 1
User is null
+----+----------+--------+-----------+
| id | priority | User | peak_rows |
+----+----------+--------+-----------+
| 1 | 2 | [null] | 1 |
| 2 | 1 | [null] | 1 |
| 6 | 1 | Mike | 0 |
| 3 | 3 | Tony | 1 |
| 4 | 2 | John | 0 |
| 5 | 2 | Andy | 0 |
+----+----------+--------+-----------+
This is what I guess I can do
select
id,
CASE WHEN priority = 1 THEN 1 ELSE 0 END as c1,
CASE WHEN User is NULL THEN 1 ELSE 0 END as c2,
c1 + c2 AS peak_rows
FROM mytable
ORDER BY peak_rows DESC
but it cause an error:
ERROR: column "c1" does not exist
LINE 5: c1+ c2as pp
^
SQL state: 42703
Character: 129
I don't know why I make 2 columns(c1 and c2), but I can not use it later.
Any good idea to do that?
You are not making two columns and using them later, you are making them and want to use them at the same time. You could use a subquery.
SELECT a.id, a.priority, a.User, a.c1 + a.c2 AS peak_rows
FROM
(SELECT id,
priority,
User,
CASE WHEN priority = 1 THEN 1 ELSE 0 END as c1,
CASE WHEN User IS NULL THEN 1 ELSE 0 END as c2,
FROM mytable) a
ORDER BY peak_rows DESC;
select
id,
CASE WHEN priority = 1 THEN 1 ELSE 0 END as c1,
CASE WHEN User is NULL THEN 1 ELSE 0 END as c2,
(CASE WHEN priority = 1 THEN 1 ELSE 0) + ( CASE WHEN User is NULL THEN 1 ELSE 0 END) AS peak_rows
FROM mytable
ORDER BY peak_rows DESC
I suppose your aim is to order by those c1 and c2, so you can directly use in the order by clause. You just need to interchange 0 and 1 in the case..when statements. And depending on your priority=1 criteria id=2 must stay at the top.
with mytable( id, priority, "User" ) as
(
select 1 , 2, null union all
select 2, 1, null union all
select 3, 3, 'Tony' union all
select 4, 2, 'John' union all
select 5, 2, 'Andy' union all
select 6, 1, 'Mike'
)
select *
from mytable
order by ( case when priority = 1 then 0 else 1 end ) +
( case when "User" is null then 0 else 1 end );
id priority User
-- -------- -------
2 1 [null]
1 2 [null]
6 1 Mike
3 3 Tony
4 2 John
5 2 Andy
Demo

Count each condition within group

For every unique GroupId I would like to get a count of each IsGreen, IsRound, IsLoud condition and a total number of rows.
Sample data:
-----------------------------------------------------
id | ItemId | GroupId | IsGreen | IsRound | IsLoud
----+--------+---------+---------+---------+---------
1 | 1001 | 1 | 0 | 1 | 1
2 | 1002 | 1 | 1 | 1 | 0
3 | 1003 | 2 | 0 | 0 | 0
4 | 1004 | 2 | 1 | 0 | 1
5 | 1005 | 2 | 0 | 0 | 0
6 | 1006 | 3 | 0 | 0 | 0
7 | 1007 | 3 | 0 | 0 | 0
Desired result:
----------------------------------------------------------
GroupId | TotalRows | TotalGreen | TotalRound | TotalLoud
--------+-----------+------------+------------+-----------
1 | 2 | 1 | 2 | 1
2 | 3 | 1 | 0 | 1
3 | 2 | 0 | 0 | 0
I'm using the following code to create the table, the problem I'm having is that if any of the groups have no rows that match one of the conditions that group does not appear in the final table. What is the best way to accomplish what I want to do?
SELECT total.GroupId
, total.[Count] AS TotalRows
, IsGreen.[Count] AS TotalGreen
, IsRound.[Count] AS TotalRound
, IsLoud.[Count] AS TotalLoud
FROM (
SELECT GroupId
, count(*) AS [Count]
FROM TestData
GROUP BY GroupId
) TotalRows
INNER JOIN (
SELECT GroupId
, count(*) AS [Count]
FROM TestData
WHERE IsGreen = 1
GROUP BY GroupId
) IsGreen ON IsGreen.GroupId = TotalRows.GroupId
INNER JOIN (
SELECT GroupId
, count(*) AS [Count]
FROM TestData
WHERE IsRound = 1
GROUP BY GroupId
) IsRound ON IsRound.GroupId = TotalRows.GroupId
INNER JOIN (
SELECT GroupId
, count(*) AS [Count]
FROM TestData
WHERE IsLoud = 1
GROUP BY GroupId
) IsLoud ON IsLoud.GroupId = TotalRows.GroupId
You can use count to count rows per each [GroupId] and sum to count each property .
select [GroupId]
, count([GroupId]) as [TotalRows]
, sum([IsGreen]) as [TotalGreen]
, sum([IsRound]) as [TotalRound]
, sum([IsLoud]) as [TotalLoud]
from [TestData]
group by [GroupId]
Use conditional Aggregate. Try this.
SELECT GroupId,
Count(GroupId) TotalRows,
Count(CASE WHEN IsGreen = 1 THEN 1 END) TotalGreen,
Count(CASE WHEN IsRound = 1 THEN 1 END) TotalRound,
Count(CASE WHEN IsLoud = 1 THEN 1 END) TotalLoud
FROM tablename
GROUP BY GroupId

Return all rows from a table and indicate with a new column whether they exist or not in another table

If I have 2 tables:
TABLE_SEARCHFIELDS:
FieldID | FieldName
--------------------
1 | MyField1
2 | MyField2
3 | MyField3
4 | MyField4
5 | MyField5
and
TABLE_CUSTOMSEARCHFIELDS:
UserID | FieldID
--------------------
1 | 1
1 | 2
1 | 5
2 | 2
2 | 4
2 | 5
and I would like to return all of the Searchfields from the first table, but would also like indicated whether that Searchfield is active for a particular user.
E.g. I want to query UserID = 1 and get the result:
FieldID | FieldName | Active
------------------------------
1 | MyField1 | 1
2 | MyField2 | 1
3 | MyField3 | 0
4 | MyField4 | 0
5 | MyField5 | 1
What is the best way to achieve this?
I would do this using exists:
select sf.*,
(case when exists (select 1
from customsearchfields csf
where csf.userid = 1 and csf.fieldid = sf.fieldid
)
then 1 else 0
end) as Active
from searchfields sf;
Assuming you have no duplicate rows, you can also do this using a left join:
select sf.*, (case when csf.userid is not null then 1 else 0 end) as Active
from searchfields sf left join
customsearchfields csf
on csf.userid = 1 and csf.fieldid = sf.fieldid;

SQL Select records excluding some statuses

I'm totally stuck on how to create this select. I need to select from the status table only those order_id's which to not have status 2.
Here is the table:
+----+---------+---------+--
| id | order_id| status |
+----+---------+---------+--
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 1 |
| 4 | 2 | 2 |
| 5 | 3 | 1 |
| 1 | 3 | 3 |
| 2 | 4 | 2 |
| 3 | 4 | 1 |
| 4 | 4 | 2 |
| 5 | 5 | 3 |
+----+---------+----------+--
So he select result will be only order_id = 5
Please help!
If you want to include orders with status 1 and exclude those with status 3, then you can use a similar idea:
having sum(case when status_id = 1 then 1 else 0 end) > 0 and
sum(case when status_id = 3 then 1 else 0 end) = 0
EDIT: I like to EXCLUDE those order_id's:
- Which has only status 1 (not status 2)
- and
- which has status 3
Lets have table like this:
id--order-id-Prod---Status
------------------------------
1 1 a 1
6 1 b 2
7 1 a 2
8 1 b 1
9 2 a 1
10 3 a 1
11 3 b 1
12 3 a 2
13 3 b 2
14 4 a 1
15 4 b 1
16 5 a 1
17 5 b 1
18 5 a 2
19 5 b 2
20 5 a 3
21 5 b 3
Select should show only order_id "5"
This is an example of a set-within-sets query:
select order_id
from t
group by order_id
having sum(case when status = 2 then 1 else 0 end) = 0
The having clause counts the number of rows with a status of 2. The = 0 finds the orders with no matches.
EDIT:
If you want to include orders with status 1 and exclude those with status 3, then you can use a similar idea:
having sum(case when status_id = 1 then 1 else 0 end) > 0 and
sum(case when status_id = 3 then 1 else 0 end) = 0
Here's one way.
Select * from TableName
where Order_ID not in (Select order_ID from tableName where status=2)
Another way would be to use the not exists clause.
Another way is to use EXCEPT:
SELECT order_id
FROM StatusTable
EXCEPT
SELECT order_id
FROM StatusTable
WHERE status = 2;
It works in SQL-Server and Postgres (and in Oracle if you replace the EXCEPT with MINUS.)
I think this works, one query to select all ids, one to get those with a status of 2 and left joining on order_id and picking those with null order_id in the list of orders with a status of 2.
select
all_ids.order_id
from
(
select distinct
order_id
from status
) all_ids
left join
(
select
order_id
from status
where status = 2
) two_ids
on all_ids.order_id = two_ids.order_id
where two_ids.order_id is null