mysql limit with inner join and subquery - mysql

I have the following query:
SELECT saturday_combinations.index, v.val AS `row` , COUNT( * ) AS `count`
FROM saturday_combinations
INNER JOIN (
SELECT ONE AS val
FROM saturday_combinations
WHERE ONE IS NOT NULL
UNION
SELECT TWO AS val
FROM saturday_combinations
WHERE TWO IS NOT NULL
UNION
SELECT THREE AS val
FROM saturday_combinations
WHERE THREE IS NOT NULL
UNION
SELECT FOUR AS val
FROM saturday_combinations
WHERE FOUR IS NOT NULL
UNION
SELECT FIVE AS val
FROM saturday_combinations
WHERE FIVE IS NOT NULL
UNION
SELECT SIX AS val
FROM saturday_combinations
WHERE SIX IS NOT NULL
UNION
SELECT SEVEN AS val
FROM saturday_combinations
WHERE SEVEN IS NOT NULL
) v ON v.val = saturday_combinations.ONE
OR v.val = saturday_combinations.TWO
OR v.val = saturday_combinations.THREE
OR v.val = saturday_combinations.FOUR
OR v.val = saturday_combinations.FIVE
OR v.val = saturday_combinations.SIX
OR v.val = saturday_combinations.SEVEN
GROUP BY v.val
The purpose of the query is to provide a count of the different values contained in the columns ONE,TWO,THREE,FOUR,FIVE,SIX and SEVEN in the table saturday_combinations. However I want to put a desc limit 4 so that it only performs the count based on the last 4 rows (last four maximum indexes). But I am not getting it to work with the union. Adding order and limit at the very end only limits from the final select, rather than get the last 4 rows and calculate the distribution on them. Any tips?
The table schema is as follows:
index | ONE|TWO|THREE|FOUR|FIVE|SIX|SEVEN
1 1 3 7 10 11 12 13
2 3 4 5 30 31 22 23
3 1 2 3 4 5 6 7
4 1 2 3 4 5 6 7
5 1 2 3 4 5 6 7
6 1 2 3 4 5 6 7
7 1 2 3 4 5 6 7
8 1 2 3 4 5 6 7
9 1 2 3 4 5 6 7
10 1 2 3 4 5 6 7
Index is auto-increment and ONE-SEVEN has integer values.
There are about 3000 rows in the table and I want to count occurences for each value based on the last n rows.
Ideal result for the last n rows where n = last 3 rows should be
Numbers|Count
1 3
2 3
3 3
4 3
5 3
6 3
7 3
If I increase n to include last 6 rows their count should increase. If I could last 10 rows the count should increase and other numbers should appear with their count.
Here is a link to a sample of the real table.
http://sqlfiddle.com/#!2/d035b

If answer to my comment is yes then, you could try the following. When you need to add limit, order by to union selects you need to wrap union queries with brackets ().
SQLFIDDLE DEMO
Code:
(SELECT ONE AS val
FROM saturday_combinations
WHERE ONE IS NOT NULL
order by ONE desc limit 4)
UNION
(SELECT TWO AS val
FROM saturday_combinations
WHERE TWO IS NOT NULL
order by TWO desc limit 4)
UNION
(SELECT THREE AS val
FROM saturday_combinations
WHERE THREE IS NOT NULL
order by THREE desc limit 4)
If answer to my comment is no, then please clarify.
Here is the code based on your sample date:
select distinct x.one as uniqunumbers,
count(x.one) as counts
from(
sELECT DISTINCT 'one'
AS col1, one FROM sat_comb
UNION ALL
SELECT DISTINCT 'two'
AS col1, two FROM sat_comb
UNION ALL
SELECT DISTINCT 'three'
AS col1, three FROM sat_comb
) as x
group by x.one;
UNIQUNUMBERS COUNTS
1 1
3 2
4 1
5 1
7 1
EDIT as per OP has clarified and updated the question.
Quoted: "However I want to limit it so that it first takes the last n rows and then does the count on the values in those n rows. This means, if I have 3 columns with 3000 rows and 35 integers randomly appearing in these 3000 rows it should count how many times each integer appears."
SQLFIDDLE DEMO2
Query:
select x.one as uniqunumbers,
count(x.one) as counts
from(
(sELECT DISTINCT 'one'
AS col1, one FROM sat_comb
order by id desc limit 4)
UNION ALL
(SELECT DISTINCT 'two'
AS col1, two FROM sat_comb
order by id desc limit 4)
UNION ALL
(SELECT DISTINCT 'three'
AS col1, three FROM sat_comb
order by id desc limit 4)
UNION ALL
(SELECT DISTINCT 'four'
AS col1, four FROM sat_comb
order by id desc limit 4)
UNION ALL
(SELECT DISTINCT 'five'
AS col1, five FROM sat_comb
order by id desc limit 4)
UNION ALL
(SELECT DISTINCT 'six'
AS col1, six FROM sat_comb
order by id desc limit 4)
UNION ALL
(SELECT DISTINCT 'seven'
AS col1, seven FROM sat_comb
order by id desc limit 4)
) as x
group by x.one;
Output:
UNIQUNUMBERS COUNTS
2 4
3 3
4 3
5 4
6 4
8 3
9 4
20 3

Maybe I am missing something in your request but based on your desired result, why not just unpivot the data and perform the count.
select value, count(*) Total
from
(
select 'one' col, one value
from saturday_combinations
union all
select 'two' col, two value
from saturday_combinations
union all
select 'three' col, three value
from saturday_combinations
union all
select 'four' col, four value
from saturday_combinations
union all
select 'five' col, five value
from saturday_combinations
union all
select 'six' col, six value
from saturday_combinations
union all
select 'seven' col, seven value
from saturday_combinations
) src
group by value
See SQL Fiddle with Demo
The result of your sample is:
| VALUE | TOTAL |
-----------------
| 1 | 1 |
| 3 | 2 |
| 4 | 1 |
| 5 | 1 |
| 7 | 1 |
| 10 | 1 |
| 11 | 1 |
| 12 | 1 |
| 13 | 1 |
| 22 | 1 |
| 23 | 1 |
| 30 | 1 |
| 31 | 1 |
Edit #1: Based on your update this might be want you what:
select value, count(*)
from
(
select col, value
from
(
select 'one' col, one value
from saturday_combinations
order by one
limit 3
) one
union all
select col, value
from
(
select 'two' col, two value
from saturday_combinations
order by two desc
limit 3
) two
union all
select col, value
from
(
select 'three' col, three value
from saturday_combinations
order by three
limit 3
) three
union all
select col, value
from
(
select 'four' col, four value
from saturday_combinations
order by four
limit 3
) four
union all
select col, value
from
(
select 'five' col, five value
from saturday_combinations
order by five
limit 3
) five
union all
select col, value
from
(
select 'six' col, six value
from saturday_combinations
order by six
limit 3
) six
union all
select col, value
from
(
select 'seven' col, seven value
from saturday_combinations
order by seven
limit 3
) seven
) src
group by value
See SQL Fiddle with Demo
Result:
| VALUE | COUNT(*) |
--------------------
| 1 | 3 |
| 2 | 1 |
| 3 | 4 |
| 4 | 4 |
| 5 | 3 |
| 6 | 3 |
| 7 | 3 |

In case you want to look at the final solution:
http://sqlfiddle.com/#!2/867a6/13
Thanks to #bonCodigo for all the help

Related

MySQL - Ordering Values inside a field [duplicate]

I have table:
+-----+------------+--------------+
| id | title | numbers |
| 2 | Title 1 | 2,8,5 |
| 3 | Title 2 | 50,7,9,4 |
+-----+------------+--------------+
Is it possible to sort within the column? In this case in column numbers.
I need to output ordered numbers column as follows:
+-----+------------+--------------+
| id | title | numbers |
| 2 | Title 1 | 2,5,8 |
| 3 | Title 2 | 4,7,9,50 |
+-----+------------+--------------+
Something like:
SELECT id, title, SORT_FUNC(numbers) from table
I was looking for some function in MySQL documentation, but I found nothing.
It is possible, but not really a good idea.
As an example, you can split a comma separated list up by generating a range of numbers and using that with SUBSTRING_INDEX to get each element. However the range of numbers needs to be as big as the max number of delimited values.
You could then use GROUP_CONCAT to join the list back together in the right order. Note that the order will be different depending on whether you have cast the split up values as numbers / integers or left them as strings.
SELECT id, title, GROUP_CONCAT(aNumber ORDER BY aNumber)
FROM
(
SELECT id, title, CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(numbers, ',', tens.acnt * 10 + units.acnt + 1), ',', -1) AS UNSIGNED) AS aNumber
FROM some_table
CROSS JOIN
(SELECT 0 AS acnt UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) units
CROSS JOIN
(SELECT 0 AS acnt UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) tens
WHERE LENGTH(numbers) - LENGTH(REPLACE(numbers, ',', '')) >= tens.acnt * 10 + units.acnt
) sub0
GROUP BY id, title;
Demonstrated here on SQL fiddle (if SQL fiddle decides to work):-
http://www.sqlfiddle.com/#!9/c9703ee/4
First select is casting the values as integers to sort them numerically, 2nd one isn't casting them but just leaving them as strings, hence the sort order is different.

how to count how many times a number is repeated and more than one column

example::
JOHN | 1 | 6 | 2
PETER | 1 | 7 | 6
MARK | 2 | 1 | 6
DIANNA | 3 | 2 | 1
SPIDERMAN | 4 | 1 | 6
JAMIE FOXX | 5 | 1 | 6
how can I do a select count how many times that the numbers are repeated in each of the 3 columns
Example:
number 1 is repeated 6 times.
the number 6 is repeated 5 times.
Assuming your number column are c1,c2 and c3 and the table is t.
select c,count(*)
from ( select c1 as c from t
union all select c2 from t
union all select c3 from t
) t
group by c
;
Assuming you are looking for 1
A way is using union and sum
select sum(num) from
(
select count(*) as num
from my_table
where col1 = 1
union all
select count(*)
from my_table
where col2 = 1
union all
select count(*)
from my_table
where col3 = 1
) t
SELECT COUNT(CASE WHEN col1 = #number THEN 1 END) +
COUNT(CASE WHEN col2 = #number THEN 1 END) +
COUNT(CASE WHEN col3 = #number THEN 1 END) as repeat
FROM YourTable, (SELECT #number := 1) as parameter

Auto insert rows with repeated data, following two patterns

I have a table that looks like this:
| id | letter | number |
|-----|--------|--------|
| 1 | a | 1 |
| 2 | b | 1 |
| 3 | c | 1 |
| 4 | d | 1 |
| 5 | a | 2 |
| 6 | b | 2 |
| 7 | c | 2 |
| 8 | d | 2 |
| 9 | a | 3 |
| 10 | b | 3 |
| 11 | c | 3 |
| 12 | d | 3 |
|etc..| | |
I'm trying to make an SQL statement that auto-fills the table following this pattern up to id 456.
So the letters are ABCD ABCD until the sequence ends, and each 'group' of 4 has a number, that should reach 114.
I'm not sure what the best way to tackle this is, any suggestions would be appreciated.
You can use the following sql script to insert the values required into your table:
INSERT INTO target (id, letter, `number`)
SELECT rn, col, (rn - 1) % 4 + 1 AS seq
FROM (
SELECT col, #rn := #rn + 1 AS rn
FROM (
SELECT 'a' AS col UNION ALL SELECT 'b' UNION ALL
SELECT 'c' UNION ALL SELECT 'd') AS t
CROSS JOIN (
SELECT 1 AS x UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 ) AS t1
CROSS JOIN (
SELECT 1 AS x UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 ) AS t2
CROSS JOIN (SELECT #rn := 0) AS var ) AS s
WHERE rn <= 456
The above query creates a numbers table of 121 rows using a 11 x 11 cartesian product. These rows are cross joined with in-line table ('a'), ('b'), ('c'), ('d') to produce a total of 484 rows. The outer query selects just the rows needed, i.e. 456 rows in total.
Note: If you want to insert values:
id, letter, number
1 'a' 1
2 'b' 1
3 'c' 1
4 'd' 1
5 'a' 2
6 'b' 2
7 'c' 2
8 'd' 2
... etc
instead of values:
id, letter, number
1 'a' 1
2 'b' 2
3 'c' 3
4 'd' 4
5 'a' 1
6 'b' 2
7 'c' 3
8 'd' 4
... etc
then simply replace (rn - 1) % 4 + 1 AS seq with (rn - 1) DIV 4 + 1 AS seq.
Demo here
It would help if you had a numbers table of some sort. Here is one method using cross join and some arithmetic:
select (#rn := #rn + 1) as id, l.letter, (n1 + n2*5 + n3*25) as number
from (select 0 as n union all select 1 as n union all select 2 as n union all select 3 union all select 4
) n1 cross join
(select 0 as n union all select 1 as n union all select 2 as n union all select 3 union all select 4
) n2 cross join
(select 0 as n union all select 1 as n union all select 2 as n union all select 3 union all select 4
) n3 cross join
(select 'a' as letter union all select 'b' union all select 'c' union all select 'd'
) l cross join
(select #rn := 0) params
where n1 + n2*5 + n3*25 < 114;

MySQL - sort comma separated string in column

I have table:
+-----+------------+--------------+
| id | title | numbers |
| 2 | Title 1 | 2,8,5 |
| 3 | Title 2 | 50,7,9,4 |
+-----+------------+--------------+
Is it possible to sort within the column? In this case in column numbers.
I need to output ordered numbers column as follows:
+-----+------------+--------------+
| id | title | numbers |
| 2 | Title 1 | 2,5,8 |
| 3 | Title 2 | 4,7,9,50 |
+-----+------------+--------------+
Something like:
SELECT id, title, SORT_FUNC(numbers) from table
I was looking for some function in MySQL documentation, but I found nothing.
It is possible, but not really a good idea.
As an example, you can split a comma separated list up by generating a range of numbers and using that with SUBSTRING_INDEX to get each element. However the range of numbers needs to be as big as the max number of delimited values.
You could then use GROUP_CONCAT to join the list back together in the right order. Note that the order will be different depending on whether you have cast the split up values as numbers / integers or left them as strings.
SELECT id, title, GROUP_CONCAT(aNumber ORDER BY aNumber)
FROM
(
SELECT id, title, CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(numbers, ',', tens.acnt * 10 + units.acnt + 1), ',', -1) AS UNSIGNED) AS aNumber
FROM some_table
CROSS JOIN
(SELECT 0 AS acnt UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) units
CROSS JOIN
(SELECT 0 AS acnt UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) tens
WHERE LENGTH(numbers) - LENGTH(REPLACE(numbers, ',', '')) >= tens.acnt * 10 + units.acnt
) sub0
GROUP BY id, title;
Demonstrated here on SQL fiddle (if SQL fiddle decides to work):-
http://www.sqlfiddle.com/#!9/c9703ee/4
First select is casting the values as integers to sort them numerically, 2nd one isn't casting them but just leaving them as strings, hence the sort order is different.

how to sort words by letters in mysql

I have a table like this...
mytbl(names)values('ron'),('sam'),('john'),('tony')
Now,I want to see the words from the names column where each word will be sorted by letters in alphabetically ascending order.I'm trying to clarify my requirements more specifically..
I want like this
'ron' will be sorted as 'nor'
'sam' will be sorted as 'ams'
'john' will be sorted as 'hjno'
'tony' will be sorted as 'noty'
and I want see exactly those sorted values as my output.How shall I get that...how should I select from the table to get such output?
Please solve my problem.thanks in advance.
You can do that in pure SQL with the help of a tally(numbers) table which you can easily create and populate like this
CREATE TABLE tally(n INT NOT NULL PRIMARY KEY);
INSERT INTO tally
SELECT a.N + b.N * 10 + 1 n
FROM
(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) a
,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) b
ORDER BY n
Now the query
SELECT names, GROUP_CONCAT(letter ORDER BY letter SEPARATOR '') sorted_name
FROM
(
SELECT names, MID(names, n.n, 1) letter
FROM mytbl e JOIN tally n
ON n.n <= CHAR_LENGTH(names)
) q
GROUP BY names
Output:
| NAMES | SORTED_NAME |
|-------|-------------|
| john | hjno |
| ron | nor |
| sam | ams |
| tony | noty |
Here is SQLFiddle demo