Transpose row-columns and Counting number of instances per column in SQLITE - sql

I have a table structured as
|creationDate|rule. |position|
|01.01.2018 |squid:S1132|12 |
|01.01.2018 |squid:S1132|14 |
|01.01.2018 |squid:S1132|19 |
|01.01.2018 |squid:S1121|12 |
|01.01.2018 |squid:S1121|14 |
|01.02.2018 |squid:S1130|12 |
My goal is to count the number of rules per date, reporting them in different columns.
|creationDate| S1132 | S1121 | S1130 |
|01.01.2018 | 3 |2 | 0 |
|01.02.2018 | 0 |0 | 1 |
I have a total of 180 rules...
Is it possible to make it in a single query?
Running this query
select creationDate , count("creationDate") as "squid:S1132"
from SONAR_ISSUES
where rule='squid:S1132' group by creationDate
I obtain this result
|creationDate|S1132 |
|01.01.2018 |3 |
I can do a similar query for each rule, but then, I am not able to merge them...

try by using case when
select creationDate ,count(case when rule='squid:S1132' then 1 end) as S1132,
count(case when rule='squid:S1121' then 1 end) as S1121,
count(case when rule='squid:S1130' then 1 end) as S1130
from SONAR_ISSUES
group by
creationDate

You can try using conditional aggregation
DEMO
select
creationDate,
count(case when rule='squid:S1132' then "creationDate" end) as "squid:S1132",
count(case when rule='squid:S1121' then "creationDate" end) as "squid:S1121" ,
count(case when rule='squid:S1130' then "creationDate" end) as "squid:S1130"
from SONAR_ISSUES
group by creationDate

Related

Identify Sequence of Events In BigQuery

I needed help with some logic for the following dataset:
ID | POST10 | EVENTS_TIMESTAMP |
1 | picked | 2022.11.06 1:00pm|
1 | profile| 2022.11.06 1:30pm|
1 | front | 2022.11.06 1:35pm|
2 | profile| 2022.11.06 1:00pm|
2 | profile| 2022.11.06 1:30pm|
2 | front | 2022.11.06 1:35pm|
2 | front | 2022.11.06 1:36pm|
3 | picked | 2022.11.06 1:00pm|
3 | front | 2022.11.06 1:30pm|
3 | profile| 2022.11.06 1:35pm|
3 | front | 2022.11.06 1:36pm|
LOGIC SHOULD BE:
FOR A PERSON, FIRST VALUE SHOULD BE "picked", THEN "profile" AND IN BETWEEN THOSE TWO VALUES, "front" did not occur.** It can occur after or before those two(based on timestamp) but not in between.
ANSWER FOR THE DATASET ABOVE WOULD BE:
ID | ANSWER |
1 | SELECTED |
2 | NOT SELECTED|
3 | NOT SELECTED|
I wrote the sql but the greater/less than(<,>) arnt working as expected. It looks at the second part after AND individually. I need it to look inside the same window between picked and profile
(case when
(min(case when (post10) like '%picked%' then EVENTS_TIMESTAMP else null end) over (partition by (ID))
>=
min(case when (post10) like '%profile%' then EVENTS_TIMESTAMP else null end) over (partition by (ID)))
AND
(min(case when (post10) like '%profile%' then EVENTS_TIMESTAMP else null end) over (partition by (ID))
>=
min(case when (post10) like '%front%' then EVENTS_TIMESTAMP else null end) over (partition by (ID)))
then 'SELECTED'
else 'NOT SELECTED' end) as ANSWER
You might consider below
SELECT ID, IF(COUNTIF(flag) > 0, 'SELECT', 'NOT SELECTED') AS ANSWER
FROM (
SELECT *, POST10 = 'picked' AND LEAD(POST10) OVER w = 'profile' AS flag
FROM sample_table
WINDOW w AS (PARTITION BY ID ORDER BY PARSE_DATETIME('%Y.%m.%d %l:%M%p', EVENT_TIMESTAMP))
)
GROUP BY ID;
Query results

How to apply different conditions for same column and output as new columns in Postgresql?

I have a Postgres table that looks like below
ip | up_score
-----------------+-------------------
223.110.181.122 | 1
242.123.249.85 | 0
10.110.11.1 | 1
10.254.253.1 | 1
19.7.40.40 | 0
242.123.249.85 | 1
10.110.11.1 | 1
19.7.40.40 | 0
10.254.253.1 | 0
223.110.181.122 | 0
19.7.40.40 | 0
10.254.253.1 | 1
Now I want a separate count of 0s and 1s per ip. I tried the queries below
select ip, count(up_score) from net_score where up_score = 0 group by ip;
select ip, count(up_score) from net_score where up_score = 1 group by ip;
But I want to combine these two queries together such that on a single execution I get the below result
ip | count_1 | count_0
-----------------+------------+-----------
223.110.181.122 | 1 | 1
242.123.249.85 | 1 | 1
10.110.11.1 | 2 | 0
10.254.253.1 | 2 | 1
19.7.40.40 | 0 | 3
How can I do this?
You could use a filter clause, something like this (untested):
select ip,
count(*) filter (where up_score = 0) AS count_0,
count(*) filter (where up_score = 1) AS count_1
from net_score group by ip;
edit: unfortunately above does not work for postgres <9.4
Thanks to #w08r for his solution, but I found a simpler solution here (https://dba.stackexchange.com/a/112797/258199) that uses case expression. I modified it for my own use and used it. I am posting the query below
SELECT ip,
COUNT(case when up_score = 0
then ip end) as count_0,
COUNT(case when up_score = 1
then ip end) as count_1
FROM net_score
GROUP BY ip;

How Can I Count the Number of Times that Different Values Occur in a Column if the Possible Values Are Not Known?

Given the table of items
id | lccnumber | libraryid
--------------------------------------+------------------------+--------------------------------------
d6f7c1ba-a237-465e-94ed-f37e91bc64bd | PR6056.I4588 | 5d78803e-ca04-4b4a-aeae-2c63b924518b
1714f71f-b845-444b-a79e-a577487a6f7d | RC60 .A5 | 5d78803e-ca04-4b4a-aeae-2c63b924518b
1b6d3338-186e-4e35-9e75-1b886b0da53e | PR6056.I4588 | 5d78803e-ca04-4b4a-aeae-2c63b924518b
4428a37c-8bae-4f0d-865d-970d83d5ad55 | PR6056.I4588 | c2549bb4-19c7-4fcc-8b52-39e612fb7dbe
7212ba6a-8dcf-45a1-be9a-ffaa847c4423 | TK5105.88815 .A58 2004 | 5d78803e-ca04-4b4a-aeae-2c63b924518b
100d10bf-2f06-4aa0-be15-0b95b2d9f9e3 | TK5105.88815 .A58 2004 | c2549bb4-19c7-4fcc-8b52-39e612fb7dbe
is there a SQL query that will produce the result set
lccnumber | 5d78803e-ca04-4b4a-aeae-2c63b924518b | c2549bb4-19c7-4fcc-8b52-39e612fb7dbe
------------------------+--------------------------------------+--------------------------------------
PR6056.I4588 | 2 | 1
RC60 .A5 | 1 | 0
TK5105.88815 .A58 2004 | 1 | 1
If the possible libraryids are known ahead of time, then I could do something like
SELECT lccNumber,
SUM(CASE WHEN libraryId = 5d78803e-ca04-4b4a-aeae-2c63b924518b THEN 1 ELSE 0) AS 5d78803e-ca04-4b4a-aeae-2c63b924518b,
SUM(CASE WHEN libraryId = c2549bb4-19c7-4fcc-8b52-39e612fb7dbe THEN 1 ELSE 0) AS c2549bb4-19c7-4fcc-8b52-39e612fb7dbe
FROM items
GROUP BY lccNumber;
but I am looking for a solution in the case that they are not known ahead of time. One approach that would probably work is to first query for the possible libraryIds and then programmatically construct a SELECT clause that accounts for all of these values, but I am wondering if there is a simpler or more efficient way to accomplish it.
You can put the values on separate rows:
SELECT lccNumber, libraryId, COUNT(*)
FROM items
GROUP BY lccNumber, libraryId;
Then re-arrange them at the application layer. You can combine these into records and aggregate into an array for each lccNumber:
SELECT lccNumber, ARRAY_AGG( (libraryId, cnt) )
FROM (SELECT lccNumber, libraryId, COUNT(*) as cnt
FROM items
GROUP BY lccNumber, libraryId
) l
GROUP BY lccNumber

sql Properly grouping my table

I'm using MS Access in order to play around with tables through SQL. I want to properly group my table and this is an example of what I want to do. Say I have a table like this:
Cool? | Age
Yes | 15
No | 34
No | 12
Yes | 26
Yes | 10
What I want is the resulting table to show how many ppl are cool or not grouped by age. For instance in this example it would be:
AGE | Count that are cool | Count that is Not cool
<25 | 2 | 1
>=25 | 1 | 1
Thanks in advance!
Try this:
case when age<25 then '<25' when age>=25 then '>=25' end as age, count(case when age<25 then 1 else null end) as [Count that are cool], count(case when age>=25 then 1 else null end) as [Count that is Not cool]
from Table1
group by case when age<25 then '<25' when age>=25 then '>=25' end

Postgres recursive CTE or crosstab function

I try to generate some user statistics from a table that includes logging information.
**TABLE users**
user_id | user_name
-------------------
1 | julia
2 | bob
3 | sebastian
**TABLE logs**
user_id | action | timepoint
------------------------------------
1 | create_quote | 2015-01-01
1 | send_quote | 2015-02-03
1 | create_quote | 2015-02-02
1 | start_job | 2015-01-15
2 | start_job | 2015-02-23
2 | send_quote | 2015-03-04
2 | start_job | 2014-12-02
My desired output is the following table
user_id | username | create_quote | send_quote | start_job
-----------------------------------------------------------
1 | julia |2 | 1 | 1
2 | bob |0 | 1 | 1
3 | sebastian |0 | 0 | 0
It includes all users (even if there was nothing logged), but only the actions between date '2015-01-01' and '2015-05-31'. Actions are counted/grouped by action type and user.
The SQL statement could look someting like
SELECT * FROM myfunction() WHERE to_char(timepoint, 'YY/MM') BETWEEN '15/01' AND '15/05';
Do you have any idea how to manage this? I've been trying around with CTEs and recursion as well as with the crosstab function but could not find any solution.
I think the crosstab function would be a lot more elegant, but in the case that you don't have the extension loaded or, like me, struggle with the syntax, this is a kind of clumsy, brute-force way you could do it:
CREATE OR REPLACE FUNCTION get_stats(
from_date date,
thru_date date)
RETURNS table (
user_id integer,
username text,
create_quote bigint,
send_quote bigint,
start_job bigint
) AS
$BODY$
select
l.user_id, u.username,
sum (case when action = 'create_quote' then 1 else 0 end) as create_quote,
sum (case when action = 'send_quote' then 1 else 0 end) as send_quote,
sum (case when action = 'start_job' then 1 else 0 end) as start_job
from
logs l
join users u on l.user_id = u.user_id
where
l.timepoint between from_date and thru_date
group by
l.user_id, u.username
$BODY$
LANGUAGE sql VOLATILE
COST 100
ROWS 1000;
And then your query would be:
select * from get_stats('2015-01-01', '2015-05-31')
Personally, I would skip the function and just create it as a query, but it's conceivable there are reasons where you would want the function wrapper.
-- EDIT --
Based on an attempted edit, I see you may be okay with a query. Also, you wanted users that have no entries.
With all of that in mind, I think this might work:
select
u.user_id, u.username,
sum (case when action = 'create_quote' then 1 else 0 end) as create_quote,
sum (case when action = 'send_quote' then 1 else 0 end) as send_quote,
sum (case when action = 'start_job' then 1 else 0 end) as start_job
from
users u
left join logs l on
l.user_id = u.user_id and
l.timepoint between '2015-01-01' and '2015-05-31'
group by
u.user_id, u.username