SELECT CASE to return accumulative results - mysql
I'm trying to create a query using SELECT CASE that would return the accumulative results.
Here is my query, it works but doesnt return the correct result.
SELECT total, count(*) as count FROM
(
SELECT case
WHEN ( X ) < 1 THEN '1 km'
WHEN ( X ) < 3 THEN '3 km'
WHEN ( X ) < 5 THEN '5 km'
WHEN ( X ) < 10 THEN '10 km'
WHEN ( X ) < 15 THEN '15 km'
WHEN ( X ) < 25 THEN '25 km'
WHEN ( X ) < 50 THEN '50 km'
WHEN ( X ) < 100 THEN '100 km'
WHEN ( X ) > 0 THEN '-1'
else '-2'
end AS `total`
FROM `store` AS d WHERE d.pending!='1'
) AS someRandomAliasHere
GROUP BY `total`
X is a formula i'm using to calculate radius from a lat and lang. total is NOT a column in my database table, just a result to calculations of X
The query above gives me this..
1 km (4)
3 km (19)
5 km (103)
25 km (540)
50 km (61)
....
4,19,103,540,62 are the total matches found.
The total count for 3 should be 19+4=23.
5 should be 103+19+4=122 etc. And WHEN ( X ) > 0 THEN '-1' should show the total count. of matches
I tried using BETWEEN 0 AND 1, BETWEEN 0 AND 3 etc but it still didn't give me the correct results
Any ideas?
Another approach is to calculate the results independently then union them:
SELECT 1 AS total, COUNT(*) AS cnt FROM `store` WHERE store.pending != 1 AND ( X ) < 1
UNION ALL
SELECT 3 AS total, COUNT(*) AS cnt FROM `store` WHERE store.pending != 1 AND ( X ) < 3
UNION ALL
SELECT 5 AS total, COUNT(*) AS cnt FROM `store` WHERE store.pending != 1 AND ( X ) < 5
UNION ALL
/** ... **/
SELECT 100 AS total, COUNT(*) AS cnt FROM `store` WHERE store.pending != 1 AND ( X ) < 100
In addition to the accumulation, you also want a total value at the end with -1. This is a bit of a pain, but it can be accomplished.
The simplest way to do cumulative sums in MySQL is using variables. The basic idea is this:
SELECT total, cnt, (#cnt := #cnt + cnt) as count
FROM (SELECT (case WHEN ( X ) < 1 THEN '1'
WHEN ( X ) < 3 THEN '3'
WHEN ( X ) < 5 THEN '5'
WHEN ( X ) < 10 THEN '10'
WHEN ( X ) < 15 THEN '15'
WHEN ( X ) < 25 THEN '25'
WHEN ( X ) < 50 THEN '50'
WHEN ( X ) < 100 THEN '100'
WHEN ( X ) > 0 THEN '-1'
else '-2'
end) AS total, COUNT(*) as cnt
FROM store s
WHERE s.pending <> '1'
GROUP BY total
) t CROSS JOIN
(SELECT #cnt := 0) vars
ORDER BY total;
The issue with this is that you will not get an overall total of the non-negative values. Let me assume that you have no negative values. This requires adding another row into the total line:
SELECT total, cnt, (#cnt := #cnt + cnt) as count
FROM (SELECT (case WHEN ( X ) < 1 THEN '1'
WHEN ( X ) < 3 THEN '3'
WHEN ( X ) < 5 THEN '5'
WHEN ( X ) < 10 THEN '10'
WHEN ( X ) < 15 THEN '15'
WHEN ( X ) < 25 THEN '25'
WHEN ( X ) < 50 THEN '50'
WHEN ( X ) < 100 THEN '100'
WHEN ( X ) > 0 THEN '-1'
else '-2'
end) AS total, COUNT(*) as cnt
FROM store s
WHERE s.pending <> '1'
GROUP BY `total`
UNION ALL
SELECT -1, 0
) t CROSS JOIN
(SELECT #cnt := 0) vars
ORDER BY (total >= 0) desc, total;
I've changed the order by as well. Note that the value -2 is probably meaningless, because X < 1 and X > 0 cover all possible values of X (except for NULL). If you actually have values 100 or greater, there are some small changes to refine the query. You do not describe what to do with those values, so clarification on the question would be helpful.
Not sure if this works since I don't have a database to test this on. Also not exactly in the format you want.
select sum(if(X<1,1,0)) as C1,
sum(if(X<3,1,0)) as C3,
sum(if(X<5,1,0)) as C5,
sum(if(X<10,1,0)) as C10,
sum(if(X<15,1,0)) as C15,
sum(if(X<25,1,0)) as C25,
sum(if(X<50,1,0)) as C50,
sum(if(X<100,1,0)) as C100,
sum(if(X>=100,1,0)) as C100P
from store
where store.pending != '1'
Unfortunatelly MySQL do not have analytical functions and windowed functions, but in this case, you can achieve your goal using a variable and a nested subquery:
SELECT
total,
cnt,
#rollupCount:=#rollupCount+cnt AS rollupCount
FROM
(
SELECT
total,
count(*) AS cnt
FROM
(
SELECT
CASE
WHEN ( X ) < 1 THEN '1'
WHEN ( X ) < 3 THEN '3'
WHEN ( X ) < 5 THEN '5'
WHEN ( X ) < 10 THEN '10'
WHEN ( X ) < 15 THEN '15'
WHEN ( X ) < 25 THEN '25'
WHEN ( X ) < 50 THEN '50'
WHEN ( X ) < 100 THEN '100'
WHEN ( X ) > 0 THEN '-1'
ELSE '-2'
END AS `total`
FROM
`store` AS d
WHERE
d.pending != '1'
) AS someRandomAliasHere
GROUP BY
`total`
) AS anotherRandomAliasHere
, (SELECT #rollupCount:=0) AS RC
ORDER BY
total ASC
This is the same as when you want to calculate the row number for each record:
SELECT
#rowNumber:=#rowNumber+1 AS rowNumber,
sourceColumns
FROM
sourceTable, (SELECT #rowNumber:=0) AS t
ORDER BY
orderColumn;
A column to give cumulative totals from an existing query can be created relatively simply:
SELECT X,
total,
(SELECT SUM(total)
FROM (<<<your_current_query>>>) ycq2
WHERE ycq2.X <= ycq1.X) `cumulative_total`
FROM (<<<your_current_query>>>) ycq1
Of course this will expand quite a lot when pasting your current query in the two marked places.
See SQL fiddle demo.
try this:
/sql server version/
DECLARE #GROUPS TABLE (TOTAL INT)
INSERT INTO #GROUPS
VALUES (1),
(3),
(5),
(10),
(15),
(25),
(50),
(100),
(-1)
SELECT a.TOTAL, z.[COUNT] FROM #GROUPS a
CROSS APPLY
(SELECT COUNT(*) as [COUNT] FROM store x WHERE CASE WHEN a.TOTAL = -1 THEN -x.X ELSE x.X END < REPLACE(a.TOTAL,-1,0)
AND pending != 1) z
/mysql version/
CREATE TEMPORARY TABLE GROUPS TABLE (TOTAL INT)
INSERT INTO GROUPS
VALUES (1),
(3),
(5),
(10),
(15),
(25),
(50),
(100),
(-1)
SELECT a.TOTAL, z.[COUNT] FROM GROUPS a
CROSS APPLY
(SELECT COUNT(*) as [COUNT] FROM store x WHERE CASE WHEN a.TOTAL = -1 THEN -x.X ELSE x.X END < REPLACE(a.TOTAL,-1,0)
AND pending != 1) z
try this one :
1.) value after "THEN" must be numeric
2.) make temporary table with running id (example for SQL SERVER)
SELECT identity(int, 1, 1) as id,
case
WHEN ( X ) < 1 THEN 1
WHEN ( X ) < 3 THEN 3
WHEN ( X ) < 5 THEN 5
WHEN ( X ) < 10 THEN 10
WHEN ( X ) < 15 THEN 15
WHEN ( X ) < 25 THEN 25
WHEN ( X ) < 50 THEN 50
WHEN ( X ) < 100 THEN 100
WHEN ( X ) > 0 THEN -1
else '-2' end AS total
Into storeID
FROM store AS d
WHERE d.pending!='1'
Order BY total
3.) join table with same table, with criteria
Select a.*, sum(b.total) as NewTotal
From storeID a
Left Join storeID b
On b.id <= a.id
Group By a.id, a.total
4.) i think, "NewTotal" is what you are looking for
Your question is a bit hard to understand. Is this what you want?
CREATE TABLE Totals (X INT, SUM INT);
INSERT INTO Totals VALUES
(1, 4),
(3, 19),
(5, 103),
(25, 540),
(50, 61)
SELECT first.X
, Sum(second.SUM)
FROM Totals first
JOIN Totals second
ON first.x >= second.x
GROUP BY first.X
UNION
SELECT 0, SUM(sum) * 2
FROM Totals
http://sqlfiddle.com/#!3/65665/12
I suppose that you X function returns a floating point number. If I understand your logic correctly, you want to group together values where X is >=0 and <1, where X >=0 and <3, >=0 and <5 and so on, and you want to return -1 when the value is >=0, and -2 when the value is a negative <0 number.
I would use an intervals table, defined like this:
CREATE TABLE intervals (
i_begin INT,
i_end INT,
i_value INT
);
INSERT INTO intervals VALUES
(0, 1, 1),
(0, 3, 3),
(0, 5, 5),
(0, 10, 10),
(0, 15, 15),
(0, 25, 25),
(0, 50, 50),
(0, 100, 100),
(0, null, -1),
(null, 0, -2);
or you can play with values in this table to make it suite your needs.
then you can just use an INNER JOIN and a GROUP BY query:
SELECT
i_value, COUNT(*)
FROM
store INNER JOIN intervals
ON ((i_begin IS NULL OR X>=i_begin) AND (i_end IS NULL OR X<i_end))
WHERE
store.pending<>1
GROUP BY
i_value
Please see an example here.
Related
Print Prime Numbers with SQL query
I am new to StackOverflow and have got stuck with a query to print prime numbers from 2 to 1000. I have used the below query need input if this is the most efficient way to code it. WITH NUM AS ( SELECT LEVEL N FROM DUAL CONNECT BY LEVEL <= 1000 ) SELECT LISTAGG(B.N,'-') WITHIN GROUP(ORDER BY B.N) AS PRIMES FROM ( SELECT N, CASE WHEN EXISTS ( SELECT NULL FROM NUM N_INNER WHERE N_INNER .N > 1 AND N_INNER.N < NUM.N AND MOD(NUM.N, N_INNER.N)=0 ) THEN 'NO PRIME' ELSE 'PRIME' END IS_PRIME FROM NUM ) B WHERE B.IS_PRIME='PRIME' AND B.N!=1; I know this question has been asked multiple times and I am requesting better solution if any. More over need input on how this works with MySQL/MS SQL/PostgreSQL. Any help will make my understanding better.
In PostgreSQL probably the most fastest query that prints prime numbers up to 1000 is: SELECT regexp_split_to_table('2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997',E',')::int AS x ; It took only 16 ms on my computer. Note: a list of prime numbers was copied from https://en.wikipedia.org/wiki/Prime_number and pasted into this long string If you prefer SQL, then this works WITH x AS ( SELECT * FROM generate_series( 2, 1000 ) x ) SELECT x.x FROM x WHERE NOT EXISTS ( SELECT 1 FROM x y WHERE x.x > y.x AND x.x % y.x = 0 ) ; It's two times slower - 31 ms. Ans an equivalent version for Oracle: WITH x AS( SELECT level+1 x FROM dual CONNECT BY LEVEL <= 999 ) SELECT x.x FROM x WHERE NOT EXISTS ( SELECT 1 FROM x y WHERE x.x > y.x AND remainder( x.x, y.x) = 0 ) ;
The most obvious improvement is that instead of checking from 1 to n you can check from 1 to the square root of n. A second major optimization would be to use a temporary table to store the results and check them first. This way you can iterate incrementally from 1 to n, and only check the known primes from 1 to square root of n (recursively doing that until you have a list). If you go about things this way you would probably want to set up the prime detection in a function and then do the same with your number series generator. That second one though means extending SQL and so I don't know if that fits your requirements. For postgresql I would use generate_series go generate the list of numbers. I would then create functions which would then either store the list of primes in a temporary table or pass them back in and out in an ordered array and then couple them like that
MariaDB (with sequence plugin) Similar to kordirkos algorithm: select 2 as p union all select n.seq from seq_3_to_1000_step_2 n where not exists ( select 1 from seq_3_to_32_step_2 q where q.seq < n.seq and n.seq mod q.seq = 0 ); Using LEFT JOIN: select 2 as p union all select n.seq from seq_3_to_1000_step_2 n left join seq_3_to_32_step_2 q on q.seq < n.seq and n.seq mod q.seq = 0 where q.seq is null; MySQL There are no sequence generating helpers in MySQL. So the sequence tables have to be created first: drop temporary table if exists n; create temporary table if not exists n engine=memory select t2.c*100 + t1.c*10 + t0.c + 1 as seq from (select 0 c union all select 1 c union all select 2 c union all select 3 c union all select 4 c union all select 5 c union all select 6 c union all select 7 c union all select 8 c union all select 9 c) t0, (select 0 c union all select 1 c union all select 2 c union all select 3 c union all select 4 c union all select 5 c union all select 6 c union all select 7 c union all select 8 c union all select 9 c) t1, (select 0 c union all select 1 c union all select 2 c union all select 3 c union all select 4 c union all select 5 c union all select 6 c union all select 7 c union all select 8 c union all select 9 c) t2 having seq > 2 and seq % 2 != 0; drop temporary table if exists q; create temporary table if not exists q engine=memory select * from n where seq <= 32; alter table q add primary key seq (seq); Now similar queries can be used: select 2 as p union all select n.seq from n where not exists ( select 1 from q where q.seq < n.seq and n.seq mod q.seq = 0 ); select 2 as p union all select n.seq from n left join q on q.seq < n.seq and n.seq mod q.seq = 0 where q.seq is null; sqlfiddle
Oracle and without inner select in getting part: with tmp(id) as ( select level id from dual connect by level <= 100 ) select t1.id from tmp t1 JOIN tmp t2 on MOD(t1.id, t2.id) = 0 group by t1.ID having count(t1.id) = 2 order by t1.ID ;
/* Below is my solution */ /* Step 1: Get all the numbers till 1000 */ with tempa as ( select level as Num from dual connect by level<=1000 ), /* Step 2: Get the Numbers for finding out the factors */ tempb as ( select a.NUm,b.Num as Num_1 from tempa a , tempa b where b.Num<=a.Num ), /*Step 3:If a number has exactly 2 factors, then it is a prime number */ tempc as ( select Num, sum(case when mod(num,num_1)=0 then 1 end) as Factor_COunt from tempb group by Num ) select listagg(Num,'&') within group (order by Num) from tempc where Factor_COunt=2 ;
Tested on sqlite3 WITH nums(n) AS ( SELECT 1 UNION ALL SELECT n + 1 FROM nums WHERE n < 100 ) SELECT n FROM ( SELECT n FROM nums ) WHERE n NOT IN ( SELECT n FROM nums JOIN ( SELECT n AS n2 FROM nums ) WHERE n <> 1 AND n2 <> 1 AND n <> n2 AND n2 < n AND n % n2 = 0 ORDER BY n ) AND n <> 1 Tested on Vertica 8 WITH seq AS ( SELECT ROW_NUMBER() OVER() AS n FROM ( SELECT 1 FROM ( SELECT date(0) + INTERVAL '1 second' AS i UNION ALL SELECT date(0) + INTERVAL '100 seconds' AS i ) _ TIMESERIES tm AS '1 second' OVER(ORDER BY i) ) _ ) SELECT n FROM (SELECT n FROM seq) _ WHERE n NOT IN ( SELECT n FROM ( SELECT s1.n AS n, s2.n AS n2 FROM seq AS s1 CROSS JOIN seq AS s2 ORDER BY n, n2 ) _ WHERE n <> 1 AND n2 <> 1 AND n <> n2 AND n2 < n AND n % n2 = 0 ) AND n <> 1 ORDER BY n
This is what worked for me in the SQL server. I tried to reduce the order of my nested loops. declare #var int declare #i int declare #result varchar (max) set #var = 1 select #result = '2&3&5' --first few obvious prime numbers while #var < 1000 --the first loop begin set #i = 3; while #i <= #var/2 --the second loop which I attempted to reduce the order begin if #var%#i = 0 break; if #i=#var/2 begin set #result = #result + '&' + CAST(#var AS VARCHAR) break; end else set #i = #i + 1 end set #var = #var + 1; end print #result
SELECT LISTAGG(PRIME_NUMBER,'&') WITHIN GROUP (ORDER BY PRIME_NUMBER) FROM ( SELECT L PRIME_NUMBER FROM ( SELECT LEVEL L FROM DUAL CONNECT BY LEVEL <= 1000 ), ( SELECT LEVEL M FROM DUAL CONNECT BY LEVEL <= 1000 ) WHERE M <= L GROUP BY L HAVING COUNT(CASE WHEN L/M = TRUNC(L/M) THEN 'Y' END ) = 2 ORDER BY L );
SELECT GROUP_CONCAT(NUMB SEPARATOR '&') FROM ( SELECT #num:=#num+1 as NUMB FROM information_schema.tables t1, information_schema.tables t2, (SELECT #num:=1) tmp ) tempNum WHERE NUMB<=1000 AND NOT EXISTS( SELECT * FROM ( SELECT #nu:=#nu+1 as NUMA FROM information_schema.tables t1, information_schema.tables t2, (SELECT #nu:=1) tmp1 LIMIT 1000 ) tatata WHERE FLOOR(NUMB/NUMA)=(NUMB/NUMA) AND NUMA<NUMB AND NUMA>1 )
MySQL Code : DECLARE #i INT, #a INT, #count INT, #p nvarchar(max) SET #i = 1 WHILE (#i <= 1000) BEGIN SET #count = 0 SET #a = 1 WHILE (#a <= #i) BEGIN IF (#i % #a = 0) SET #count = #count + 1 SET #a = #a + 1 END IF (#count = 2) SET #P = CONCAT(#P,CONCAT(#i,'&')) SET #i = #i + 1 END PRINT LEFT(#P, LEN(#P) - 1)
The below code works to find prime numbers in SQL Tested on SampleDB of local server CREATE procedure sp_PrimeNumber(#number int) as begin declare #i int declare #j int declare #isPrime int set #isPrime=1 set #i=2 set #j=2 while(#i<=#number) begin while(#j<=#number) begin if((#i<>#j) and (#i%#j=0)) begin set #isPrime=0 break end else begin set #j=#j+1 end end if(#isPrime=1) begin SELECT #i end set #isPrime=1 set #i=#i+1 set #j=2 end end I have created the stored procedure which has a parameter #number to find the prime numbers up to that given number In order to get the prime numbers we can execute the below stored procedure EXECUTE sp_PrimeNumber 100 -- gives prime numbers up to 100 If you are new to stored procedures and want to find the prime numbers in SQL we can use the below code Tested on master DB declare #i int declare #j int declare #isPrime int set #isPrime=1 set #i=2 set #j=2 while(#i<=100) begin while(#j<=100) begin if((#i<>#j) and (#i%#j=0)) begin set #isPrime=0 break end else begin set #j=#j+1 end end if(#isPrime=1) begin SELECT #i end set #isPrime=1 set #i=#i+1 set #j=2 end This code can give the prime numbers between 1 to 100. If we want to find more prime numbers edit the #i and #j arguments in the while loop and execute
Simple query in PostgreSQL: SELECT serA.el AS prime FROM generate_series(2, 100) serA(el) LEFT JOIN generate_series(2, 100) serB(el) ON serA.el >= POWER(serB.el, 2) AND serA.el % serB.el = 0 WHERE serB.el IS NULL Enjoy! :)
For SQL Server We can use below CTE SET NOCOUNT ON ;WITH Prim AS ( SELECT 2 AS Value UNION ALL SELECT t.Value+1 AS VAlue FROM Prim t WHERE t.Value < 1000 )SELECT * FROM Prim t WHERE NOT EXISTS( SELECT 1 FROM prim t2 WHERE t.Value % t2.Value = 0 AND t.Value != t2. Value) OPTION (MAXRECURSION 0)
One simple one can be like this select level id1 from dual connect by level < 2001 minus select distinct id1 from (select level id1 from dual connect by level < 46) t1 inner join (select level id2 from dual connect by level < 11) t2 on 1=1 where t1.id1> t2.id2 and mod(id1,id2)=0 and id2<>1
Simplest method For SQL Server DECLARE #range int = 1000, #x INT = 2, #y INT = 2 While (#y <= #range) BEGIN while (#x <= #y) begin IF ((#y%#x) =0) BEGIN IF (#x = #y) PRINT #y break END IF ((#y%#x)<>0) set #x = #x+1 end set #x = 2 set #y = #y+1 end
MySQL QUERY SOLUTION I have solved this problem in mysql which is following: SET #range = 1000; SELECT GROUP_CONCAT(R2.n SEPARATOR '&') FROM ( SELECT #ctr2:=#ctr2+1 "n" FROM information_schema.tables R2IS1, information_schema.tables R2IS2, (SELECT #ctr2:=1) TI WHERE #ctr2<#range ) R2 WHERE NOT EXISTS ( SELECT R1.n FROM ( SELECT #ctr1:=#ctr1+1 "n" FROM information_schema.tables R1IS1, information_schema.tables R1IS2, (SELECT #ctr1:=1) I1 WHERE #ctr1<#range ) R1 WHERE R2.n%R1.n=0 AND R2.n>R1.n ) Note: No. of information_schema.tables should be increased for more range e.g. if range is 100000 so set the info tables by checking yourself.
--Create Table prime_number_t create table prime_number_t ( integervalue_c integer not null primary key ); --Insert Data into table prime_number_t INSERT ALL into prime_number_t(integervalue_c) values (1) into prime_number_t(integervalue_c) values (2) into prime_number_t(integervalue_c) values (3) into prime_number_t(integervalue_c) values (4) into prime_number_t(integervalue_c) values (5) into prime_number_t(integervalue_c) values (6) into prime_number_t(integervalue_c) values (7) into prime_number_t(integervalue_c) values (8) into prime_number_t(integervalue_c) values (9) into prime_number_t(integervalue_c) values (10) SELECT 1 FROM DUAL; COMMIT; --Write an SQL statement to determine which of the below numbers are prime numbers --same query works for REMAINDER function also instead of MOD function WITH cte_prime_number_t AS ( select integervalue_c from prime_number_t order by integervalue_c ), cte_maxval AS ( select max(integervalue_c) AS maxval FROM cte_prime_number_t ), cte_level AS ( select LEVEL+1 as lvl from dual, cte_maxval CONNECT BY LEVEL <= cte_maxval.maxval ) SELECT DISTINCT cpnt.integervalue_c as PrimeNumbers FROM cte_prime_number_t cpnt inner join cte_level cl on lvl <= (SELECT maxval FROM cte_maxval) WHERE NOT EXISTS ( SELECT 1 FROM cte_level cpn WHERE cpnt.integervalue_c > cpn.lvl AND mod(cpnt.integervalue_c,cpn.lvl) = 0 ) order by PrimeNumbers;
For MySQL 8 or above /* create a table with one row and that starts with 2 ends at 1000*/ SET cte_max_recursion_depth = 1001; /* works for MySQL 8.0*/ ;WITH RECURSIVE sequence AS ( SELECT 1 AS l UNION ALL SELECT l + 1 AS value FROM sequence WHERE sequence.l < 1000 ), /* create a caretesian product of a number to other numbers uptil this very number so for example if there is a value 5 in a row then it creates these rows using the table below (5,2), (5,3), (5,4), (5,5) */ J as ( SELECT (a.l) as m , (b.l) as n FROM sequence a, sequence b WHERE b.l <= a.l) , /*take a row from column 1 then divide it with other column values but group by column 1 first, note the completely divisible count*/ f as ( SELECT m , SUM(CASE WHEN mod(m,n) = 0 THEN 1 END) as fact FROM J GROUP BY m HAVING fact = 2 ORDER BY m ASC /*this view return numbers in descending order so had to use order by*/ ) /* this is for string formatting, converting a column to a string with separator &*/ SELECT group_concat(m SEPARATOR '&') FROM f;
This worked for me in MySql: select '2&3&5&7&11&13&17&19&23&29&31&37&41&43&47&53&59&61&67&71&73&79&83&89&97&101&103&107&109&113&127&131&137&139&149&151&157&163&167&173&179&181&191&193&197&199&211&223&227&229&233&239&241&251&257&263&269&271&277&281&283&293&307&311&313&317&331&337&347&349&353&359&367&373&379&383&389&397&401&409&419&421&431&433&439&443&449&457&461&463&467&479&487&491&499&503&509&521&523&541&547&557&563&569&571&577&587&593&599&601&607&613&617&619&631&641&643&647&653&659&661&673&677&683&691&701&709&719&727&733&739&743&751&757&761&769&773&787&797&809&811&821&823&827&829&839&853&857&859&863&877&881&883&887&907&911&919&929&937&941&947&953&967&971&977&983&991&997'; Well, I know the above one is just hardcoded and you will be able to run the problem but it's not what we should go for as a programmer so here is my solution for oracle: SELECT LISTAGG(L1,'&') WITHIN GROUP (ORDER BY L1) FROM (Select L1 FROM (SELECT LEVEL L1 FROM DUAL CONNECT BY LEVEL<=1000) Where L1 <> 1 MINUS select L1 from (SELECT LEVEL L1 FROM DUAL CONNECT BY LEVEL<=1000) A , (SELECT LEVEL L2 FROM DUAL CONNECT BY LEVEL<=1000) B Where L2<=L1 and MOD(L1,L2)=0 AND L1<>L2 AND L2<>1);
Worked in Oracle: SELECT LISTAGG(a,'&') WITHIN GROUP (ORDER BY a) FROM(WITH x AS( SELECT level+1 x FROM dual CONNECT BY LEVEL <= 999 ) SELECT x.x as a FROM x WHERE NOT EXISTS ( SELECT 1 FROM x y WHERE x.x > y.x AND remainder( x.x, y.x) = 0 ));
SELECT GROUP_CONCAT(distinct PRIME_NUMBER SEPARATOR '&') FROM (SELECT #prime:=#prime + 1 AS PRIME_NUMBER FROM information_schema.tables CROSS JOIN (SELECT #prime:=1) r WHERE #num <1000 ) p WHERE NOT EXISTS ( SELECT * FROM (SELECT #divisor := #divisor + 1 AS DIVISOR FROM information_schema.tables CROSS JOIN (SELECT #divisor:=1) r1 WHERE #divisor <=1000 ) d WHERE MOD(PRIME_NUMBER, DIVISOR) = 0 AND PRIME_NUMBER != DIVISOR) ; enter code here Explanation: The two inner SELECTs (SELECT #prime and SELECT #divisor) create two lists. Both of them contain numbers from 1 to 1000. The first list is the "list of potential primes" and the second is the "list of divisors" Then, we iterate over the list of the potential primes (the outer SELECT), and for each number from this list we look for divisors (SELECT * FROM clause) that can divide the number without a reminder and are not equal to the number (WHERE MOD... clause). If at least one such divisor exists, the number is not prime and is not selected (WHERE NOT EXISTS... clause).
MySQL Limit Rows / Group By
I have searched a lot of different posts about this and i didn't find something that works for me. This Using LIMIT within GROUP BY to get N results per group? and http://www.sqlines.com/mysql/how-to/get_top_n_each_group didn't work for me. I have a simple MySQL Table with the following columns id , package, user_id, date I want to perform a query in which i will get X Rows / user_id WHERE date > Number Order By date ASC In short, we want to perform a Group By user_id with LIMIT of X rows / group but have in mind the statement using the date column Example Full Table: id , package, user_id, date 1, full, 1 , 1447003159 2, full, 1 , 1447003055 3, full, 1 , 1447002022 4, full, 1 , 1447001013 5, full, 1 , 1447000031 6, mid, 2 , 1447003159 7, mid, 2 , 1447003055 8, mid, 2 , 1447002022 9, mid, 2 , 1447001013 10, mid, 2 , 1447000031 From the above table we want to Select only 2 rows / user_id but where date >= 1447000031 (But make ORDER BY date ASC first) Expected Output: 4, full, 1 , 1447001013 3, full, 1 , 1447002022 9, mid, 2 , 1447001013 8, mid, 2 , 1447002022
E.g.: SELECT x.* FROM my_table x JOIN my_table y ON y.id >= x.id AND y.user_id = x.user_id WHERE y.date > 1447000031 GROUP BY x.id HAVING COUNT(*) <= 2; or, faster, but more typing... SELECT id , package , user_id , date FROM ( SELECT x.* , CASE WHEN #prev_user = user_id THEN #i:=#i+1 ELSE #i:=1 END rank , #prev_user := user_id FROM my_table x , ( SELECT #prev_user = 0,#i:=1 ) vars WHERE date > 1447000031 ORDER BY user_id , date ) a WHERE rank <= 2;
Trying to use ID in MySQL SubSubQuery
So I'll show you what I'm trying to do and explain my problem, there may be an answer different to the approach I'm trying to take. The query I'm trying to perform is as follows: SELECT * FROM report_keywords rk WHERE rk.report_id = 231 AND ( SELECT SUM(t.conv) FROM ( SELECT conv FROM report_keywords t2 WHERE t2.campaign_id = rk.campaign_id ORDER BY conv DESC LIMIT 10 ) t ) >= 30 GROUP BY rk.campaign_id The error I get is Unknown column 'rk.campaign_id' in 'where clause' Obviously this is saying that the table alias rk is not making it to the subsubquery. What I'm trying to do is get all of the campaigns where the sum of the top 10 conversions is greater than or equal to 30. The relevant table structure is: id INT, report_id INT, campaign_id INT, conv INT Any help would be greatly appreciated. Update Thanks to Kickstart I was able to do what I wanted. Here's my final query: SELECT campaign_id, SUM(conv) as sum_conv FROM ( SELECT campaign_id, conv, #Sequence := if(campaign_id = #campaign_id, #Sequence + 1, 1) AS aSequence, #campaign_id := campaign_id FROM report_keywords CROSS JOIN (SELECT #Sequence := 0, #campaign_id := 0) Sub1 WHERE report_id = 231 ORDER BY campaign_id, conv DESC ) t WHERE aSequence <= 10 GROUP BY campaign_id HAVING sum_conv >= 30
Possibly use a user variable to add a sequence number to get the latest 10 records for each one, then use SUM to get the count of those. Something like this:- SELECT rk.* FROM report_keywords rk INNER JOIN ( SELECT campaign_id, SUM(conv) AS SumConv FROM ( SELECT campaign_id, conv, #Sequence := if(campaign_id = #campaign_id, #Sequence + 1, 1) AS aSequence, #campaign_id := campaign_id FROM report_keywords CROSS JOIN (SELECT #Sequence := 0, #campaign_id := "") Sub1 ORDER BY campaign_id, conv ) Sub2 WHERE aSequence <= 10 GROUP BY campaign_id ) Sub3 ON rk.campaign_id = Sub3.campaign_id AND Sub3.SumConv >= 30 WHERE rk.report_id = 231
MySQL SUM DISTINCT with Conditional
I need to gather sums using conditional statements as well as DISTINCT values with a multiple GROUP BY. The example below is a simplified version of a much much more complex query. Because the real query is very large, I need to avoid having to drastically re-write the query. DATA Contracts id advertiser_id status 1 1 1 2 2 1 3 3 2 4 1 1 A Query that's close SELECT COUNT( DISTINCT advertiser_id ) AS advertiser_qty, COUNT( DISTINCT id ) AS contract_qty, SUM( IF( status = 1, 1, 0 ) ) AS current_qty, SUM( IF( status = 2, 1, 0 ) ) AS expired_qty, SUM( IF( status = 3, 1, 0 ) ) AS other_qty FROM ( SELECT * FROM `contracts` GROUP BY advertiser_id, id ) AS temp Currently Returns advertiser_qty contract_qty current_qty expired_qty other_qty 3 4 3 1 0 Needs to Return advertiser_qty contract_qty current_qty expired_qty other_qty 3 4 2 1 0 Where current_qty is 2 which is the sum of records with status = 1 for only DISTINCT advertiser_ids and each sum function will need the same fix. I hope someone has a simple solution that can plug into the SUM functions. -Thanks!!
try this SELECT COUNT( DISTINCT advertiser_id ) AS advertiser_qty, COUNT( DISTINCT id ) AS contract_qty, (select count(distinct advertiser_id) from contracts where status =1 ) AS current_qty, SUM( IF( status = 2, 1, 0 ) ) AS expired_qty, SUM( IF( status = 3, 1, 0 ) ) AS other_qty FROM ( SELECT * FROM `contracts` GROUP BY advertiser_id, id ) AS temp DEMO HERE EDIT: you may look for this without subselect. SELECT COUNT(DISTINCT advertiser_id) AS advertiser_qty, COUNT(DISTINCT id) AS contract_qty, COUNT(DISTINCT advertiser_id , status = 1) AS current_qty, SUM(IF(status = 2, 1, 0)) AS expired_qty, SUM(IF(status = 3, 1, 0)) AS other_qty FROM (SELECT * FROM `contracts` GROUP BY advertiser_id, id) AS temp DEMO HERE
question about group by
in mysql how to write a sql like this, to get the amount of X > 20 and <20 select date, numberOfXMoreThan20,numberOfXLessThan20, otherValues from table group by (date, X>20 and X<20) my way, but i think it's not good select less20.id_date, a,b from (select id_date,count(Duree_Attente_Avant_Abandon) as a from cnav_reporting.contact_global where Duree_Attente_Avant_Abandon>20 group by id_date) as less20, (select id_date,count(Duree_Attente_Avant_Abandon) as b from cnav_reporting.contact_global where Duree_Attente_Avant_Abandon<20 group by id_date) as more20 where less20.id_date=more20.id_date thanks
SELECT date, SUM( IF(X > 20), 1, 0 ) AS overTwenty, SUM( IF(X < 20), 1, 0 ) AS belowTwenty, otherValue FROM `table` GROUP BY `date`, `otherValue`
You're probably looking for the COUNT aggregate: SELECT COUNT(*) FROM table Where X > 20