data_table info
idx | type | value
1 | 1 | 1
2 | 2 | 2
3 | 3 | 3
4 | 4 | 4
query
SELECT * FROM data_table WHERE idx IN (1, 1, 2, 1, 1, 3, 4, 4, 1);
I receive this current result:
idx | type | value
1 | 1 | 1
2 | 2 | 2
3 | 3 | 3
4 | 4 | 4
But I intend to receive the following result:
idx | type | value
1 | 1 | 1
1 | 1 | 1
2 | 2 | 2
1 | 1 | 1
1 | 1 | 1
3 | 3 | 3
4 | 4 | 4
4 | 4 | 4
1 | 1 | 1
How can I change my query to receive my desired result?
A potential way to solve this is creating a table on the fly and then perform a JOIN:
CREATE TEMPORARY TABLE ids (id INT NOT NULL);
INSERT INTO ids VALUES (1), (1), (2), (1), (1), (3), (4), (4), (1);
SELECT data_table.* FROM
FROM ids JOIN data_table ON data_table.idx = ids.id;
DROP ids;
I'm afraid of you should use union all to write some ugly sql:
select * from data_table where idx = 1
union all
select * from data_table where idx = 1
union all
select * from data_table where idx = 2
union all
select * from data_table where idx = 1
union all
select * from data_table where idx = 1
union all
select * from data_table where idx = 3
union all
select * from data_table where idx = 4
union all
select * from data_table where idx = 4
union all
select * from data_table where idx = 1
Or something like this:
select data_table.*
from (
select 1 idx
union all select 1
union all select 1
union all select 2
union all select 1
union all select 1
union all select 3
union all select 4
union all select 4
union all select 1
) t
left join data_table
on t.idx = data_table.idx
Note: The second way will get you different order and it's inspired by #Willem Van Onsem
If you need get rows that order, what you will hard coded, then you can simulate additional column (ord in this case) and then use this column in ORDER BY clause:
SELECT data_table.* FROM data_table
inner join (
select 1 as idx, 1 as ord
union all
select 1 as idx, 2 as ord
union all
select 2 as idx, 3 as ord
union all
select 1 as idx, 4 as ord
union all
select 1 as idx, 5 as ord
union all
select 3 as idx, 6 as ord
union all
select 4 as idx, 7 as ord
union all
select 4 as idx, 8 as ord
union all
select 1 as idx, 9 as ord
) your_list
on
data_table.idx = your_list.idx
order by your_list.ord
Related
I have following table.
Sales:
id quantity price_charged
------------------------------
101 2 100
102 3 300
103 1 120
I want to select the records such that it repeat Rows N time according to quantity column value.
So I need following results
id quantity price_charged
--------------------------------
101 1 50
101 1 50
102 1 100
102 1 100
102 1 100
103 1 120
I think, it is better to resolve not with query(SQL).
There is some generation feature, but its performance is poor.
You have to change your model(store always 1 quantity), or process it in backend(java/c/stb.)
Select id,
1 as quantity,
price_charged
from table_name t
JOIN
(SELECT e*10000+d*1000+c*100+b*10+a n FROM
(select 0 a 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) t1,
(select 0 b 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) t2,
(select 0 c 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) t3,
(select 0 d 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) t4,
(select 0 e 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) t5) counter
ON (counter.n<=t.quantity)
The joined subquery reapeted numbers from 0 to 99999 it is the burn it maximum for quantity. The join repeat by the counter 0... quantity-1 values.
I was able to come up with a solution for my problem after referring an answer for how to generate series in mysql. Here is the link.
SELECT
sal.id,
1 as quantity, sal.quantity as originalQty,
sal.price_charged/sal.quantity
FROM
(SELECT
#num := #num + 1 AS count
FROM
sales, -- this can be any table but it should have row count
-- more than what we expect the max value of Sales.quantity column
(SELECT #num := 0) num
LIMIT
100) ctr
JOIN sales sal
ON sal.quantity >= ctr.count
order by id;
If you are lucky enough to be running MySQL 8.0, you can use a recursive CTE to solve this problem. This is an elegant solution that does not require creating a list of numbers of using variables.
Consider this query:
WITH RECURSIVE cte AS (
SELECT 1 n, id, quantity, price_charged FROM sales
UNION ALL
SELECT n + 1, id, quantity, price_charged FROM cte WHERE n < quantity
)
SELECT id, quantity, price_charged/quantity quantity
FROM cte
ORDER BY id;
In this DB Fiddle with your sample data, the query returns:
| id | quantity | quantity |
| --- | -------- | -------- |
| 101 | 2 | 50 |
| 101 | 2 | 50 |
| 102 | 3 | 100 |
| 102 | 3 | 100 |
| 102 | 3 | 100 |
| 103 | 1 | 120 |
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
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;
I have the same exact question as this person, but for MySQL rather than SQL Server. Can ungrouping be done with MySQL? MySQL doesn't have an "Unpivot" function unfortunately. Here is an example of what I need:
Raw Data:
----------------------------------
owner id | name | occurances
----------------------------------
1 | red | 4
1 | yellow | 2
1 | green | 3
----------------------------------
Query to output:
---------------
id | name
---------------
1 | red
1 | red
1 | red
1 | red
1 | yellow
1 | yellow
1 | green
1 | green
1 | green
---------------
You need a set of numbers for this. Here is one way:
select id, name
from t join
(select d1.d + 10 * d2.d + 100*d3.d as num
from (select 1 as d union all select 2 union all select 3 union all
select 4 union all select 5 union all select 6
select 7 union all select 8 unin all select 9 union all select 0
) d1 cross join
(select 1 as d union all select 2 union all select 3 union all
select 4 union all select 5 union all select 6
select 7 union all select 8 unin all select 9 union all select 0
) d2 cross join
(select 1 as d union all select 2 union all select 3 union all
select 4 union all select 5 union all select 6
select 7 union all select 8 unin all select 9 union all select 0
) d3
) n
where n.num between 1 and occurrences
This works for numbers up to 999.
I have a MySQL table that looks something like this:
|---ID---|---COUNTER---|
| 1 | 2 |
| 2 | 6 |
| 3 | 1 |
| 5 | 9 |
| 6 | 10 |
I'm looking for a SELECT statement that returns ID's and their COUNTER. The table only have ID's such as: 1,2,3,5,6. Is there a statement where you say: I want ID's 1 to 10 even if they doesn't exist in the table, and if the ID doesn't exist, return the ID anyway with the COUNTER value 0. For example:
|---ID---|---COUNTER---|
| 1 | 2 |
| 2 | 6 |
| 3 | 1 |
| 4 | 0 |
| 5 | 9 |
| 6 | 10 |
| 7 | 0 |
| 8 | 0 |
| 9 | 0 |
| 10 | 0 |
Do I have to create a SELECT statement that contains NOT EXIST parameters?
Thanks in advance, Steve-O
Without creating a temp table:
select t.num as id, coalesce(yt.counter, 0)
from your_table yt
right join (
select 1 as num union select 2 union select 3 union select 4 union select 5 union
select 6 union select 7 union select 8 union select 9 union select 10
) t on yt.id = t.num
order by t.num
and bit more general:
select t.num as id, coalesce(yt.counter, 0)
from your_table yt
right join (
select t1.num + t2.num * 10 + t3.num * 100 as num
from (
select 1 as num union select 2 union select 3 union select 4 union select 5 union
select 6 union select 7 union select 8 union select 9 union select 0
) t1
cross join (
select 1 as num union select 2 union select 3 union select 4 union select 5 union
select 6 union select 7 union select 8 union select 9 union select 0
) t2
cross join (
select 1 as num union select 2 union select 3 union select 4 union select 5 union
select 6 union select 7 union select 8 union select 9 union select 0
) t3
) t on yt.id = t.num
where t.num between (select min(id) from your_table) and (select max(id) from your_table)
You can define limit by yourself here I've used min and max of id value from your_table.
It's not very robust, but if you created a temporary table with the ID's you wanted in it, you could then left join to your table containing ID and Counter which would include all the values:
Declare #tempidtable as table ( imaginaryid int )
insert into #tempidtable ( imaginaryid ) values ( 1 )
insert into #tempidtable ( imaginaryid ) values ( 2 )
insert into #tempidtable ( imaginaryid ) values ( 3 )
select
#temptable.imaginaryid,
ISNULL(yourothertable.counter, 0)
from #tempidtable
left join yourothertable
on #tempidtable.imaginaryid = yourothertable.id
As Tomek says you could loop over the inserts to make it easier to maintain, or possible store the ids you want as a base in another table, using this as the basis for the join rather than a temp table.
Create a table with all possible ID's:
create table Numbers (nr int primary key);
declare i int default 1;
while i < 100000 do
insert into Numbers (nr) values (i);
set i = i + 1;
end while;
Then you can use left join to return all numbers:
select n.NR
, c.Counter
from Numbers n
left join
Counters c
on c.ID = n.NR
You can use left join to solve your issue. Read more about left join here
I think you will have to create (generate in loop) temporary table with the complete sequence of numbers from 1 to N (where N is the MAX(Id) of counted table). Then do left join to that table and apply GROUP BY clause.
You need the range of integers to do an outer join with your table based on ID. Generating a range of integers is dependent on the SQL vendor if you do not want to use a temporary table. See SQL SELECT to get the first N positive integers for hints on how to do this based on your SQL vendor.