How do I format the "total" row of a rollup?
Backgroup
I have a MySQL select statement that is using group by with rollup it works however, for formatting reasons I need to identify what row is a "detail" and what row is a "total." Doing this by a simple RowType column that is a 1 or a zero. I figured this would work:
select
if (MyId is null, 1,0) as RowType,
MyId,
sum(Quantity) as Quantity
from MyTable
group by MyId with rollup
This does not work. However, If I create a view of that select statement then select that view and do this it does:
Create view MyView as
select
MyId,
Sum(Quantity) as Quantity
from MyTable
group by MyId with rollup;
select
if (MyId is null, 1,0) as RowType,
MyId,
Quantity
from MyView;
Is there a better way? I am going to have to do this for a fair amount of queries and maintaining two sets is good way to have errors.
edit: screwed up my second select code and fixed it
You can put the grouped query into a subquery.
This is needed because grouping doesn't happen after selecting, so the SELECT list can't refer to the value created by WITH ROLLUP in the same query.
select
if(MyId is null, 1,0) as RowType, MyId, Quantity
FROM (
SELECT MyId, sum(Quantity) as Quantity
from MyTable
group by MyId with rollup
) AS x
Related
I have this very simple table:
CREATE TABLE MyTable
(
Id INT(6) PRIMARY KEY,
Name VARCHAR(200) /* NOT UNIQUE */
);
If I want the Name(s) that is(are) the most frequent and the corresponding count(s), I can neither do this
SELECT Name, total
FROM table2
WHERE total = (SELECT MAX(total) FROM (SELECT Name, COUNT(*) AS total
FROM MyTable GROUP BY Name) table2);
nor this
SELECT Name, total
FROM (SELECT Name, COUNT(*) AS total FROM MyTable GROUP BY Name) table1
WHERE total = (SELECT MAX(total) FROM table1);
Also, (let's say the maximum count is 4) in the second proposition, if I replace the third line by
WHERE total = 4;
it works.
Why is that so?
Thanks a lot
You can try the following:
WITH stats as
(
SELECT Name
,COUNT(id) as count_ids
FROM MyTable
GROUP BY Name
)
SELECT Name
,count_ids
FROM
(
SELECT Name
,count_ids
,RANK() OVER(ORDER BY count_ids DESC) as rank_ -- this ranks all names
FROM stats
) s
WHERE rank_ = 1 -- the most popular ```
This should work in TSQL.
Your queries can't be executed because "total" is no column in your table. It's not sufficient to have it within a sub query, you also have to make sure the sub query will be executed, produces the desired result and then you can use this.
You should also consider to use a window function like proposed in Dimi's answer.
The advantage of such a function is that it can be much easier to read.
But you need to be careful since such functions often differ depending on the DB type.
If you want to go your way with a sub query, you can do something like this:
SELECT name, COUNT(name) AS total FROM myTable
GROUP BY name
HAVING COUNT(name) =
(SELECT MAX(sub.total) AS highestCount FROM
(SELECT Name, COUNT(*) AS total
FROM MyTable GROUP BY Name) sub);
I created a fiddle example which shows both queries mentioned here will produce the same and correct result:
db<>fiddle
I have a table that looks like this:
serial|vehicule|alert_emails
12411|AAA|yes
12411|BBB|yes
13411|CCC|yes
13411|DDD|yes
14411|EEE|yes
I want to do a mysql query to select all data and organize it by serial field to get a array result like this:
12411
AAA|yes
BBB|yes
13411
CCC|yes
DDD|yes
14411
EEE|yes
I tried group by the field serial but I'm not getting the desired result:
SELECT * FROM mytable GROUP BY serial;
Any help please?
Thanks.
Use UNION ALL to get the distinct serials of the table and all the rows of the table:
SELECT CASE WHEN t.col IS NULL THEN t.serial END serial, t.col
FROM (
SELECT DISTINCT serial, null AS col
FROM mytable
UNION ALL
SELECT serial, CONCAT(vehicule, '|', alert_emails)
FROM mytable
) t
ORDER BY t.serial, t.col IS NULL DESC
See the demo.
I have table with 4 records with similar event name and 2 different device ids and i want total no. of records with total unique device ids.
Mysql gives perfect result but redshift is giving incorrect data.
CREATE TABLE test (
event_name varchar(50) NOT NULL,
deviceid int NOT NULL
);
INSERT INTO test (event_name, deviceid) VALUES
('install', 1),
('install', 1),
('install', 2),
('install', 1);
select count(event_name), count(distinct(deviceid)) from test;
Mysql result
You should use Distinct without ( )
SELECT count(event_name), COUNT(Distinct deviceid)
FROM Test;
Or
SELECT count(event_name), (SELECT count(deviceid) FROM (SELECT DISTINCT deviceid FROM test)) DisCount
FROM test;
As far as I know, Redshift should process this query correctly:
select count(event_name), count(distinct deviceid)
from test;
That said, in my experience with RedShift, count(distinct) was quite slow, particularly over an entire table. (This may be been fixed.)
If this is still the case, then a simple workaround is:
select sum(cnt) as row_count, count(*) as distinct_count
from (select deviceid, count(*) as cnt
from test
group by deviceid
) t
This might be significantly faster.
We read values from a set of sensors, occasionally a reading or two is lost for a particular sensor , so now and again I run a query to see if all sensors have the same record count.
GROUP BY sensor_id HAVING COUNT(*) != xxx;
So I run a query once to visually get a value of xxx and then run it again to see if any vary.
But is there any clever way of doing this automatically in a single query?
You could do:
HAVING COUNT(*) != (SELECT MAX(count) FROM (
SELECT COUNT(*) AS count FROM my_table GROUP BY sensor_id
) t)
Or else group again by the count in each group (and ignore the first result):
SELECT count, GROUP_CONCAT(sensor_id) AS sensors
FROM (
SELECT sensor_id, COUNT(*) AS count FROM my_table GROUP BY sensor_id
) t
GROUP BY count
ORDER BY count DESC
LIMIT 1, 18446744073709551615
SELECT sensor_id,COUNT(*) AS count
FROM table
GROUP BY sensor_id
ORDER BY count
Will show a list of the sensor_id along with a count of all the records it has, you can then manually check to see if any vary.
SELECT * FROM (
SELECT sensor_id,COUNT(*) AS count
FROM table
GROUP BY sensor_id
) AS t1
GROUP BY count
Will show all the counts that vary, but the group by will lose information about which sensor_ids have which counts.
---EDIT---
Taken a bit from both mine and eggyal's answer and created this, for the count that is most frequent I call the id default, and then for any values that stand out I have given them separate rows. This way you maintain the readability of a table if you have many results Multi Row, but also have a simple one row column if all counts are the same One Row. If however you are happy with the concocted strings then go with eggyal's answer.
Might be a bit over the top but here goes:
select 'default' as id,t5.c1 as count from(
select id,count(*) as c1 from your_table group by id having count(*)=
(select t4.count from
(
select max(t3.count2) as max,t3.count as count from
(
select count(*) as count2,t2.count from
(
SELECT id,COUNT(*) AS count
FROM your_table
GROUP BY id
) as t2
GROUP BY count
) as t3
) as t4)) as t5 group by count
union all
select t5.id as id,t5.c1 as count from(
select id,count(*) as c1 from your_table group by id having count(*)<>
(select t4.count from
(
select max(t3.count2) as max,t3.count as count from
(
select count(*) as count2,t2.count from
(
SELECT id,COUNT(*) AS count
FROM your_table
GROUP BY id
) as t2
GROUP BY count
) as t3
) as t4)) as t5
I have this query to search in two SQL tables. I am looking for a way to sort the result by occurrence. This is my query:
SELECT `parent_id`
FROM wp_forum_posts
WHERE text LIKE '%{$term1}%'
UNION
SELECT `id`
FROM wp_forum_threads
WHERE subject LIKE '%{$term1}%
Which is the best way, to get the results ordered?
The trick is first to use UNION ALL, which preserves duplicates (ordinary UNION removes duplicates), then select from that result. This query should do it:
select * from (
select parent_id as mID, count(*) as cnt
from wp_forum_posts
where text like '%{$term1}%'
group by 1
UNION ALL
select id, count(*)
FROM wp_forum_threads
where subject like '%{$term1}%
group by 1) x
order by 2, 1
Assumes ID and parent_ID are not duplicates in tables otherwise you can get 2 rows per an id... and would you want them summed together if so then are parent_ID and ID related?
Select mID, cnt
FROM
(SELECT `parent_id` as mID, count(`parent_ID`) as cnt
FROM wp_forum_posts
WHERE text LIKE '%{$term1}%'
Group by `parent_ID`
UNION
SELECT `id`, count(`id`) as cnt
FROM wp_forum_threads
WHERE subject LIKE '%{$term1}%
GROUP BY `id`)
Order by cnt ASC, mID