SQL order groups of data - sql

Here I have a data sample:
Title
Size
Count
First
3
14
First
5
3
Second
2
5
First
2
10
Third
3
10
Second
3
4
Third
2
9
Third
5
11
Second
5
4
Now I want to sort the data with following rules:
Put the records with same title together: First followed by First, Second followed by Second.
Then for each group, order them by size;
For groups, order them in the sum of count of each group, like: sum of First is 14+3+10=27, Second is 5+4+4=13, Third is 10+9+11=30.
The result I want:
Title
Size
Count
Second
2
5
Second
3
4
Second
5
4
First
2
10
First
3
14
First
5
3
Third
2
9
Third
3
10
Third
5
11

It's an easy sort once you get the total "Count" per Title.
A SUM OVER can be used for that.
SELECT
q.title AS "Title"
, q.size AS "Size"
, q.count AS "Count"
FROM
(
SELECT t.title, t.size, t.count
, SUM(t.count) OVER (PARTITION BY t.title) AS TotalCount
FROM yourtable t
) q
ORDER BY q.TotalCount, q.title, q.size
Title
Size
Count
Second
2
5
Second
3
4
Second
5
4
First
2
10
First
3
14
First
5
3
Third
2
9
Third
3
10
Third
5
11
Demo on db<>fiddle here

You can join the results of the group count sums back onto the main table, using the sums in the order by clause:
select t.* from tbl t join
(select t1.title, sum(t1.cnt) s from tbl t1 group by t1.title) t2
on t.title = t2.title order by t2.s, t.title, t.size;

Another approach is by using WITH Queries (Common Table Expressions)
with ct
as (
select title
,size
,count
,sum(count) over (partition by title) sm
from tbl
)
select title
,size
,count
from ct
order by ct.sm,2;

Related

SUM a column in SQL, based on DISTINCT values in another column, GROUP BY a third column

I'd appreciate some help on the following SQL problem:
I have a table of 3 columns:
ID Group Value
1 1 5
1 1 5
1 2 10
1 2 10
1 3 20
2 1 5
2 1 5
2 1 5
2 2 10
2 2 10
3 1 5
3 2 10
3 2 10
3 2 10
3 4 50
I need to group by ID, and I would like to SUM the values based on DISTINCT values in Group. So the value for a group is only accounted for once even though it may appear multiple for times for a particular ID.
So for IDs 1, 2 and 3, it should return 35, 15 and 65, respectively.
ID SUM
1 35
2 15
3 65
Note that each Group doesn't necessarily have a unique value
Thanks
the CTE will remove all duplicates, so if there a sdiffrenet values for ID and Group, it will be counted.
The next SELECT wil "GROUP By" ID
For Pstgres you would get
WITH CTE as
(SELECT DISTINCT "ID", "Group", "Value" FROM tablA
)
SELECT "ID", SUM("Value") FROM CTE GROUP BY "ID"
ORDER BY "ID"
ID | sum
-: | --:
1 | 35
2 | 15
3 | 65
db<>fiddle here
Given what we know at the moment this is what I'm thinking...
The CTE/Inline view eliminate duplicates before the sum occurs.
WITH CTE AS (SELECT DISTINCT ID, Group, Value FROM TableName)
SELECT ID, Sum(Value)
FROM CTE
GROUP BY ID
or
SELECT ID, Sum(Value)
FROM (SELECT DISTINCT * FROM TableName) CTE
GROUP BY ID

How to find the most frequently repeated column?

ID UserID LevelID
1 1 1
2 1 2
3 1 2
4 1 2
5 2 1
6 2 3
7 3 2
8 4 1
9 4 1
The query should return: LevelID: 1 (3 times) - the LevelID column that is most frequently repeated by different Users (UserID).
I have the following query:
SELECT LevelID, COUNT(LevelID) AS 'Occurrence'
FROM
(
SELECT DISTINCT * FROM
(
SELECT UserID, LevelID
FROM SampleTable
) cv
) levels
GROUP BY LevelID
ORDER BY 'Occurrence' DESC
Which returns:
LevelID Occurence
1 3
2 2
3 1
But it doesn't let me to add LIMIT 1; at the bottom to retrieve the first top row of the selection. What's wrong with the query?
There is no need for these several levels of nesting. Consider using aggregation, count(distinct ...), ordering the results and using a row-limiting clause to keep the top record only:
select top(1) levelID, count(distinct userID) cnt
from mytable
group by levelID
order by cnt desc
If you want to allow possible top ties, then use top (1) with ties instead of just top (1).

Get ID of row from max value

I'm new in database
I have the following table:
id group factor
------------------------
1 11 1
2 11 5
4 11 2
5 12 3
6 12 2
7 13 4
8 13 1
9 13 8
10 14 6
I need to get the id of the one that has the largest factor based on its group, for example, in the case of group 11, the row with the largest factor is 5, so I need to obtain the id of that row, in this case 2.
please if someone can show me the right way.
You could use:
SELECT DISTINCT ON(group) group factor, id
FROM tab
ORDER BY group, factor DESC;
db<>fiddle demo
You can use simple CTE (Common Table Expression) for it, as in:
with
x as (
select group_id, max(factor) as max_factor from my_table group by group_id
)
select t.*
from my_table t
join x on x.group_id = t.group_id and x.max_factor = t.factor
This solution has the [desirable?] feature that in case there are multiple rows tied in first place in the same group, it will show them all, not just one [randomly] of them.
If you know the group in advance, e.g. 11, then you can simply do:
SELECT id
FROM tab
WHERE group = 11
ORDER BY factor DESC
LIMIT 1;
Otherwise if you want the result for each group that exists in the table then Lukasz Szozda's answer it the way to go.

Select Top N Random rows from table then ordering by column

I need to get 3 random rows from a table and then order those rows by a the BannerWeight column.
So if the data is:
BannerID BannerWeight
1 5
2 5
3 10
4 5
5 10
I want the results to be:
BannerID BannerWeight
5 10
2 5
4 5
So far I have:
SELECT TOP 3 b.BannerID, b.BannerWeight FROM CMS_Banner b
INNER JOIN CMS_BannerCategory c ON b.BannerCategoryID = c.BannerCategoryID
WHERE c.BannerCategoryName LIKE 'HomepageSponsors'
ORDER BY NEWID()
I just can't figure out how to order those 3 random rows once I get them. I've tried doing
ORDER BY BannerWeight, NEWID()
But this just gets me 3 random rows where the BannerWeight is 5.
Here is an SQLFiddle: http://sqlfiddle.com/#!6/a8088/2/0
Easiest option (I think) is to use a subquery:
Select * from
(
SELECT TOP 3 b.BannerID, b.BannerWeight FROM Banners b
ORDER BY NEWID()
) a
order by a.bannerweight

How to declare a row as a Alternate Row

id Name claim priority
1 yatin 70 5
6 yatin 1 10
2 hiren 30 3
3 pankaj 40 2
4 kavin 50 1
5 jigo 10 4
7 jigo 1 10
this is my table and i want to arrange this table as shown below
id Name claim priority AlternateFlag
1 yatin 70 5 0
6 yatin 1 10 0
2 hiren 30 3 1
3 pankaj 40 2 0
4 kavin 50 1 1
5 jigo 10 4 0
7 jigo 1 10 0
It is sorted as alternate group of same row.
I am Using sql server 2005. Alternate flag starts with '0'. In my example First record with name "yatin" so set AlternateFlag as '0'.
Now second record has a same name as "yatin" so alternate flag would be '0'
Now Third record with name "hiren" is single record, so assign '1' to it
In short i want identify alternate group with same name...
Hope you understand my problem
Thanks in advance
Try
SELECT t.*, f.AlternateFlag
FROM tbl t
JOIN (
SELECT [name],
AlternateFlag = ~CAST(ROW_NUMBER() OVER(ORDER BY MIN(ID)) % 2 AS BIT)
FROM tbl
GROUP BY name
) f ON f.name = t.name
demo
You could use probably an aggregate function COUNT() and then HAVING() and then UNION both Table, like:
SELECT id, A.Name, Claim, Priority, 0 as AlternateFlag
FROM YourTable
INNER JOIN (
SELECT Name, COUNT(*) as NameCount
FROM YourTable
GROUP BY Name
HAVING COUNT(*) > 1 ) A
ON YourTable.Name = A.Name
UNION ALL
SELECT id, B.Name, Claim, Priority, 1 as AlternateFlag
FROM YourTable
INNER JOIN (
SELECT Name, COUNT(*) as NameCount
FROM YourTable
GROUP BY Name
HAVING COUNT(*) = 1 ) B
ON YourTable.Name = B.Name
Now, this assumes that the Names are unique meaning the names like Yatin for example although has two counts is only associated to one person.
See my SqlFiddle Demo
You can use Row_Number() function with OVER that will give you enumeration, than use the reminder of integer division it by 2 - so you'll get 1s and 0s in your SELECT or in the view.