SQL finding difference between subqueries - mysql

I have got a table of Salaries and i have to find the difference of averages of rows with zeroes and without,so here is the my query
SELECT ((SELECT REPLACE(Salary, '0', '') FROM TEST) - (SELECT ROUND(SUM(Salary)/COUNT(*)) FROM Test)) FROM Test
Unfortunately my query is not working.
Example 5 salaries: 5049,7000,2000,3900
I have to find the average of 5049,7000,2000,3900 and 549,7,2,39

Try this:
SELECT a.without, a.with, a.with - a.without
FROM(
SELECT AVG(CAST(REPLACE(Salary, '0', '') AS INT)) AS 'without', AVG(salary)
as 'with'
FROM test) a

Related

Counting distinct dates from two columns in a single SQL table

I've been reading through the solutions of similar problems posted here, but none seem to resolve my particular issue.
I currently have a table (CT_JOINED) that includes three columns: an identifer column (TUMOURID), a date column (AVCT_DATE) and another date column (OPDATE).
As an example, the columns for two IDs look as follows:
ID, AVCT_DATE, OPDATE
1, 06-APR-13, 06-APR-13
1, 06-APR-13, 14-JUN-13
1, 06-APR-13, 22-JUN-13
2, 03-APR-14, 10-DEC-15
2, 03-APR-14, 31-DEC-15
What I'm attempting to do is create a column that is equal to the number of unique dates per ID. So the result for ID 1 would be 3 and the result for ID 2 would be 3.
I have attempted a count of distinct values across the two columns, but this does not provide the answers above (it instead reports values of 3 and 2 respectively):
select TUMOURID, COUNT(DISTINCT(AVCT_DATE || OPDATE)) AS COUNT
FROM CT_JOINED
GROUP BY TUMOURID;
The same thing happens if I try and do the same in a new table:
CREATE TABLE CT_DISTINCT AS (
SELECT TUMOURID, COUNT(*) AS COUNT
FROM (
SELECT DISTINCT TUMOURID, AVCT_DATE, OPDATE
FROM CT_JOINED)
GROUP BY TUMOURID
);
I'm at a loss. Is it possible?
You could use:
SELECT TUMOURID, COUNT(DISTINCT d) AS cnt
FROM (select TUMOURID, AVCT_DATE AS d
FROM CT_JOINED
UNION ALL
SELECT TUMOURID, OPDATE AS d) sub
GROUP BY TUMOURID;
Unpivot the data and then use count(distinct) or remove duplicates along the way:
select tumourid, count(*)
from ((select tumourid, avct_date as dte
from ct_joined
) union -- intentional to remove duplicates
(select tumourid, opdate as dte
from ct_joined
)
) t
group by tumourid;
Use UNION to avoid duplicate date & just use count(*) :
SELECT tumourid, COUNT(date)
FROM ((SELECT tumourid, avct_date AS date
FROM ct_joined
) UNION
(SELECT tumourid, opdate
FROM ct_joined
)
) t
GROUP BY tumourid;
All of the answers below work like a charm with a few tweaks to also account for rows with null values. For instance:
SELECT TUMOURID, COUNT(*)
FROM ((SELECT TUMOURID, AVCT_DATE AS DTE
FROM CT_JOINED
WHERE AVCT_DATE IS NOT NULL
) UNION
(SELECT TUMOURID, OPDATE AS DTE
FROM CT_JOINED
WHERE OPDATE IS NOT NULL
)
) T
GROUP BY TUMOURID;
Many thanks.

Select columns where isnull() is false

I have a query that works when I run it through my MySQL manager directly, however the query doesn't seem to work in my application.
I've identified the problem to be the following query:
SELECT task_id, member_id, SUM(NOT(ISNULL(completion_date))) AS complete, COUNT(id) AS total
FROM classroom_task_data
GROUP BY task_id, member_id
and specifically the SUM(NOT(ISNULL(completion_date))).
If I change it to SUM(ISNULL(completion_date)) (removed the NOT) the query works in my application. I don't know why this happens, but I figured I might as well try a different approach to get the result I want.
I tried SUM(NOT ISNULL(completion_date)) as well, but without success. I also tested out COALESCE but I couldn't get it to work.
So I'm wondering how I can write the above differently but still get the same results.
Here's the full query btw:
SELECT id, title, member_id, instruction, start_date, end_date, is_archived, is_published, classroom_id, user_id
FROM (
SELECT task_id, member_id, SUM(NOT(ISNULL(completion_date))) AS complete, COUNT(id) AS total
FROM classroom_task_data GROUP BY task_id, member_id
)
AS td
JOIN
classroom_tasks AS t ON td.task_id = t.id
WHERE complete = total AND classroom_id = 35;
An if statement would give the same result.
-0 when the completion_date is null
-1 when the completion_date is NOT null
SUM( if(completion_date IS NULL, 0, 1)) AS complete
Maybe you could try that
Try IS NOT NULL:
SUM( completion_date IS NOT NULL )
This will sum completion_date if they are not null or otherwise add it with zero.
COALESCE(SUM(completion_date),0)

Counting data based on decades

I have a table Books with a column for the release year of a book (type: year). I want to count the number of books released in every decade.
I have tried the following:
select count(*) as count, concat(decade, '-', decade + 9) as ReleaseYear
from (
select floor('ReleaseYear' / 10) * 10 as decade
from Book
) t
group by decade;
But it is returns 0 results.
When I try year('ReleaseYear') it returns nulls.
Create a decade value for each row and find the count(decade) .. group by decade.
Query
select t.decade,count(t.decade) as BooksCount from
(
select *,
concat((releaseYear - ((releaseYear % 10)-1)),'-',((releaseYear - ((releaseYear % 10)-1))+ 9)) as decade
from Books
)t
group by t.decade;
SQL Fiddle
Try;
SELECT
count(*) `count`,
concat(FLOOR(year(`ReleaseYear`)/10)*10, '-', FLOOR(year(`ReleaseYear`)/10)*10 + 9) `ReleaseYear`
from `books`
group by FLOOR(year(`ReleaseYear`)/10)*10
Demo sqlfiddle

SQL Aggregation Query

I have a dataset that I need to do some aggregation on to display.
Date, Rank, Vote
07/20/2013, 8, -1
07/21/2013, 8, -1
07/23/2013, 7, -1
07/24/2013, 6, 1
07/25/2013, 7, 1
07/26/2013, 7, -1
07/27/2013, 8, 1
07/28/2013, 8, 1
07/29/2013, 8, -1
I'd like to group by consecutive ranks, summing the vote, and choosing the first of the grouped dates. The above data set would return:
07/20/2013,8,-2
07/23/2013,7,-1
07/24/2013,6,1
07/25/2013,7,0
07/27/2013,8,1
My first thought was GROUP BY Date and Rank but that wouldn't consolidate multiple days. I can do this after the fact by looping thru the data or I can use a cursor within a stored procedure but I'm curious if there is a simpler way with a SQL query.
This does it:
SELECT firstDate, Rank, SUM(vote) Votes
FROM (
SELECT #first_date := CASE WHEN Rank = #prev_rank
THEN #first_date
ELSE Date
END firstDate,
#prev_rank := Rank curRank,
data.*
FROM (SELECT #first_date := NULL, #prev_rank := NULL) init
JOIN (SELECT Date, Rank, Vote
FROM MyTable
Order by Date) data
) grouped
GROUP BY firstDate, Rank
SQLFIDDLE
Most straightforward way I can see, is what you already pointed out.
Use the Group By SQL:
SELECT date, rank, SUM(vote) FROM YourTable
GROUP BY date, rank
Fiddle Demo: http://sqlfiddle.com/#!2/d65d5c/3
Iterate through this record set in your program and do what is needed to get your data.
(If you tag your question with a programming language, I can show you how).
So basically no, I can't see any better way to do this. As far I can see this would end up in a fairly complicated and slow SQL query. But maybe someone can teach me better.

MySQL select count by value

I have this mysql table:
DATE | VALUE
and I wish to become a select which shows me this information as:
DATE | COUNT TOTAL | COUNT VAL=1 | COUNT VAL=2
Any ideas how I can achieve this?
SELECT date,
COUNT(*),
COUNT( IF( value = 1, 1, NULL ) ),
COUNT( IF( value = 2, 1, NULL ) )
FROM my_table
I think with SUM() you can get neater code. Since it sums the values respective expression for row.
SELECT date,
COUNT(*),
SUM( value = 1 ),
SUM( value = 2 )
FROM my_table
Official Documentation can be found here.
SELECT `date`, COUNT(*) AS `COUNT TOTAL`,
COUNT(CASE `value` WHEN 1 THEN `value` END) AS `COUNT VAL=1`
COUNT(CASE `value` WHEN 2 THEN `value` END) AS `COUNT VAL=2`
FROM mytable
GROUP BY `date`
The CASE expressions will be null when there is no match. Nulls are not counted by COUNT().
I imagine you might want a dynamic number of columns, one column for each value found in the data. This is not possible in SQL. The columns must be known at the time you write the query.
So you have two options to get subtotals per value:
First query the distinct values from all rows of value and construct an SQL query dynamically, appending one column in the select-list for each distinct value you want to report. Then run this SQL query.
Alternatively, fetch all the rows as rows. Count the subtotals per value in application code.
One further alternative is to count subtotals by groups, and include totals:
SELECT `value`, `date, COUNT(*) AS `COUNT SUBTOTAL`
FROM mytable
GROUP BY `value`, `date` WITH ROLLUP
But that doesn't report the subtotals in columns as you requested, it reports the subtotals in rows.