How to produce detail, not summary, report sorted by count(*)? - sql

Oracle 11g:
I want results to list by highest count, then ch_id. When I use group by to get the count then I loose the granularity of the detail. Is there an analytic function I could use?
SALES
ch_id desc customer
=========================
ANAR Anari BOB
SWIS Swiss JOE
SWIS Swiss AMY
BRUN Brunost SAM
BRUN Brunost ANN
BRUN Brunost ROB
Desired Results
count ch_id customer
===========================================
3 BRUN ANN
3 BRUN ROB
3 BRUN SAM
2 SWIS AMY
2 SWIS JOE
1 ANAR BOB

Use the analytic count(*):
select * from
(
select count(*) over (partition by ch_id) cnt,
ch_id, customer
from sales
)
order by cnt desc

select total, ch_id, customer
from sales s
inner join (select count(*) total, ch_id from sales group by ch_id) b
on b.ch_id = s.chi_id
order by total, ch_id
ok - the other post that happened at the same time, using partition, is the better solution for Oracle. But this one works regardless of DB.

Related

array rank and group by in a SQL

Team
Greetings!
Here is my BigQuery table.
customer state questions response_displayed datetime
--------------------------------------------------------------------------------
john NY q1 answer1,answer2,answer3 22-jan
jack NJ q2 answer1,answer2,answer3 23-jan
mario OH q3 answer1,answer2 24-jan
john NY q4 answer1,answer120 25-jan
jack NJ q5 answer2 26-jan
Here I am trying to sum all questions asked by a customer, state combination, and get the most frequent response_displayed. we have to split & unnest response_dispalyed and then take the count of each response and get the 1st rank.
Here is the sample output
customer state total_question frequent_response_dispalyed
john ny 2 answer1
jack nj 2 answer2
mario oh 1 answer1,answer2
I am unable to use the unnest(split(response_dispalyed)) along with the group by function.
Any pointers would be appreciated.
Consider below approach
select * except(responses),
array_to_string(array(
select response from (
select response, count(*) frequency
from unnest(responses) response
group by response
)
where true
qualify rank() over(order by frequency desc) = 1
), ',') as frequent_response_dispalyed
from (
select customer, state, count(*) as total_question,
array_concat_agg(split(response_displayed)) as responses
from `project.dataset.table`
group by customer, state
)
if applied to sample data in your question - output is

SQL find and group consecutive number in rows without duplicate

So I have a table like this:
Taxi Client Time
Tom A 1
Tom A 2
Tom B 3
Tom A 4
Tom A 5
Tom A 6
Tom B 7
Tom B 8
Bob A 1
Bob A 2
Bob A 3
and the expected result will be like this:
Tom 3
Bob 1
I have used the partition function to count the consecutive value but the result become this:
Tom A 2
Tom A 3
Tom B 2
Bob A 2
Please help, I am not good in English, thanks!
This is a variation of a gaps-and-islands problem. You can solve it using window functions:
select taxi, count(*)
from (select t.taxi, t.client, count(*) as num_times
from (select t.*,
row_number() over (partition by taxi order by time) as seqnum,
row_number() over (partition by taxi, client order by time) as seqnum_c
from t
) t
group by t.taxi, t.client, (seqnum - seqnum_c)
having count(*) >= 2
)
group by taxi;
use distinct count
select taxi ,count( distinct cient)
from table_name
group by taxi
It seems your expected output is wrong
I don't see where you get the number 3 from. If you're trying to do what your question says and group by client in consecutive order only and then get the number of different groups, I can help you out with the following query. Bob has 1 group and Tom has 4.
Partition by taxi, ORDER BY taxi, time and check if this client matches the previous client for this taxi. If yes, do not count this row. If no, count this row, this is a new group.
SELECT FEE.taxi,
SUM(FEE.clientNotSameAsPreviousInSequence)
FROM
(
SELECT taxi,
CASE
WHEN PreviousClient IS NULL THEN
1
WHEN PreviousClient <> client THEN
1
ELSE
0
END AS clientNotSameAsPreviousInSequence
FROM
(
SELECT *,
LAG(client) OVER (PARTITION BY taxi ORDER BY taxi, time) AS PreviousClient
FROM table
) taxisWithPreviousClient
) FEE
GROUP BY FEE.taxi;

Issue with returning distinct records based on single column (Oracle)

If I have the table "members" (shown below), how would I go about getting the record of the first occurrence of a membership_id (Oracle).
Expected results
123 John Doe A P
313 Michael Casey A A
113 Luke Skywalker A P
Table - members
membership_id first_name last_name status type
123 John Doe A P
313 Michael Casey A A
113 Luke Skywalker A P
123 Bob Dole A A
313 Lucas Smith A A
SELECT membership_id,
first_name,
last_name,
status,
type
FROM( SELECT membership_id,
first_name,
last_name,
status,
type,
rank() over (partition by membership_id
order by type desc) rnk
FROM members )
WHERE rnk = 1
will work for your sample data set. If you can have ties-- that is, multiple rows with the same membership_id and the same maximum type-- this query will return all those rows. If you only want to return one of the rows where there is a tie, you would either need to add additional criteria to the order by to ensure that all ties are broken or you would need to use the row_number function rather than rank which will arbitrarily break ties.
Select A.*
FROM Members AS A inner join
(Select membership_id, first(first_name) AS FN, first(last_name) AS LN
From Members
Group by membership_id) AS B
ON A.membership_id=B.membership_id and A.first_name=B.FN and A.last_name=B.LN
Hope that helps!
select *
from members
where rowid in (
select min(rowid)
from members
group by membership_id
)

Retrieve highest value from sql table

How can retrieve that data:
Name Title Profit
Peter CEO 2
Robert A.D 3
Michael Vice 5
Peter CEO 4
Robert Admin 5
Robert CEO 13
Adrin Promotion 8
Michael Vice 21
Peter CEO 3
Robert Admin 15
to get this:
Peter........4
Robert.......15
Michael......21
Adrin........8
I want to get the highest profit value from each name.
If there are multiple equal names always take the highest value.
select name,max(profit) from table group by name
Since this type of request almost always follows with "now can I include the title?" - here is a query that gets the highest profit for each name but can include all the other columns without grouping or applying arbitrary aggregates to those other columns:
;WITH x AS
(
SELECT Name, Title, Profit, rn = ROW_NUMBER()
OVER (PARTITION BY Name ORDER BY Profit DESC)
FROM dbo.table
)
SELECT Name, Title, Profit
FROM x
WHERE rn = 1;

Ranking Students by Grade in SQL

I have a table like this:
Date StudentName Score
01.01.09 Alex 100
01.01.09 Tom 90
01.01.09 Sam 70
01.02.09 Alex 100
01.02.09 Tom 50
01.02.09 Sam 100
I need to rank the students in the result table by score within different dates, like this:
Date Student Rank
01.01.09 Alex 1
01.01.09 Tom 2
01.01.09 Sam 3
01.02.09 Alex 1
01.02.09 Sam 1
01.02.09 Tom 2
How can I do this in SQL?
You want to use the rank function in T-SQL:
select
date,
student,
rank() over (partition by date order by score desc) as rank
from
grades
order by
date, rank, student
The magic is in the over clause. See, it splits up those rankings by date, and then orders those subsets by score. Brilliant, eh?
You should use ORDER BY:
SELECT * FROM Students ORDER BY Date,Rank
That will order the data by date, then rank. You can add as many fields as you want, as long as they are comparable (you can't compare BLOBs or long text fields).
Hope that helps.
Do you know about using an ORDER BY clause?
You need to write a function that will computer the rank for a given student and date. Then you can "ORDER BY Date, Rank()"