Select data from single column as multiple record - mysql

I have the following table structure in a mysql database.
id | files | status
1 a.pdf,b.pdf,c.pdx 1
2 d.pdf,e.pdf.g.pdf 2
3 x.pdf,k.pdf,y.pdf 1
As you can see, the attachments are all stored on a single line.
My query is supposed to select all rows where status = 1 so i'm expecting the data in the following format.
1 1 a.pdf 1
2 1 b.pdf 1
3 1 c.pdf 1
4 3 x.pdf 1
5 3 k.pdf 1
6 3 y.pdf 1
Unfortunately, I am unsure which operator I can use to accomplish this. I'm aware SQL has pivot but i doubt even that can address my issue.
As a result, I would appreciate if I could get any help in the condition of the select query.
Regards

Try this:
SET #row_num = 0;
SELECT
(#row_num := #row_num + 1) ROW_NUM,
id,
SUBSTRING_INDEX(SUBSTRING_INDEX(files, ',', idx), ',', -1) FileName,
status
FROM
test
JOIN
(SELECT 1 idx UNION ALL SELECT 2 idx UNION ALL SELECT 3 idx UNION ALL SELECT 4 idx UNION ALL SELECT 5 idx) idxs
on idxs.idx - 2 < LENGTH(files) - LENGTH(REPLACE(files, ",", ""))
WHERE status = 1
;
Just add as many indexes as your max count of files in a string.
Note that there should be no comma fater last filename. This is magic -2 is responsible for.

Consider the following...
I have a table (ints) of integers (0-9)...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id SERIAL PRIMARY KEY
,files VARCHAR(100) NOT NULL
,status INT NOT NULL
);
INSERT INTO my_table VALUES
(1,'a.pdf,b.pdf,c.pdx',1),
(2,'d.pdf,e.pdf,g.pdf',2),
(3,'x.pdf,k.pdf,y.pdf',1);
SELECT DISTINCT id
, SUBSTRING_INDEX(SUBSTRING_INDEX(files,',',i2.i*10+i1.i+1),',',-1) file
, status
FROM my_table
, ints i1
, ints i2
WHERE status = 1
ORDER
BY id, i2.i*10+i1.i;
+----+-------+--------+
| id | file | status |
+----+-------+--------+
| 1 | a.pdf | 1 |
| 1 | b.pdf | 1 |
| 1 | c.pdx | 1 |
| 3 | x.pdf | 1 |
| 3 | k.pdf | 1 |
| 3 | y.pdf | 1 |
+----+-------+--------+

Related

PHPMyAdmin - Update 30k rows with looped number sequence

I hope i'm explaining this properly... but i'm trying to update a column in a table with 30k rows with a repeated sequence.
I've populated entire columns before with random numbers using:
UPDATE locations SET template = CAST((RAND() * 4)+1 AS UNSIGNED);
Which gave:
2
4
5
1
3
etc. in a random fashion throughout the 30k rows...
I would like to enter a query that can produce a repeated sequence like:
1
2
3
4
5
1
2
3
4
5
across all 30k rows.
I've been looking into loops and auto increments but can't get it to work.
Any help much appreciated :)
Perhaps using a variable will do for example
DROP TABLE IF EXISTS T;
CREATE TABLE T(ID INT, SEQNO INT);
INSERT INTO T VALUES (1,NULL),(2,NULL),(3,NULL),(4,NULL),(5,NULL),(6,NULL),(7,NULL);
UPDATE T
SET SEQNO = (SELECT IF(#RN = 2 ,#RN:=1,#RN:=#RN + 1) FROM (SELECT #RN:=0) R)
WHERE 1 = 1
+------+-------+
| ID | SEQNO |
+------+-------+
| 1 | 1 |
| 2 | 2 |
| 3 | 1 |
| 4 | 2 |
| 5 | 1 |
| 6 | 2 |
| 7 | 1 |
+------+-------+
Thanks for the suggestions... I had a hard time finding an answer but eventually found something that would do exactly what I was after. I must admit it is far beyond my capabilities, but here it is:
SET #row_number = 0;
SET #max_num = 75;
update locations loc1
join (
select
if ((num % #max_num) = 0, #max_num, (num % #max_num)) as num2,
a.*
from (
select
(#row_number:=#row_number + 1) AS num,
loc.*
from locations loc
ORDER BY num
) a
order by num, num2
) loc2 on (loc2.id = loc1.id)
set loc1.colname = loc2.num2;

MySQL missing values from column

Radio_ID | Log_ID
-----------------
1 | 1
1 | 2
1 | 4
1 | 7
1 | 10
2 | 1
2 | 2
2 | 3
2 | 5
Is it possible to get the following output in a single sql statement?
Output:
Radio_ID | Log_ID
-----------------
1 | 3
1 | 5
1 | 6
1 | 8
1 | 9
2 | 4
Logic: returns missing values for each id < max value for id (ex 10 is max value for radio id 1 and missing values are 3,5,6,8,9).
I have a data parser for a radio device and when the radio is outside the coverage area it doesn't send data, so I have to send a new request for missing Log_IDs.
Thank you!
Let me assume that you have a table called numbers with integers of a sufficient range.
Then you can do:
select r.radio_id, n.n as MissingLogId
from (select radio_id, min(log_id) as minli, max(log_id) as maxli
from table t
group by radio_id
) r join
numbers n
on n.n between r.minli and r.maxli left join
table t
on t.radio_id = r.radio_id and t.log_id = n.n
where t.radio_id is null;
The idea is to generate all the numbers for each radio id (between the minimum and maximum id) using a join. Then existing values are filtered out.
If you don't have a numbers table handy, you need to create one large enough. This would probably work:
create table numbers (n int primary key);
insert into numbers(n)
select (#rn := #rn + 1) as n
from table cross join (#rn := 0);

Split a column into a defined range in MYSQL

I have a table which looks like this:
+-----------------------
| id | first_name
+-----------------------
| AC0089 | John |
| AC0015 | Dan |
| AC0017 | Marry |
| AC0003 | Andy |
| AC0001 | Trent |
| AC0006 | Smith |
+-----------------------
I need a query to split the id in the range of 3 and also display the starting id of that range i.e.
+------------+----------+--------
| startrange | endrange | id
+------------+----------+--------
| 1 | 3 | AC0089
| 4 | 6 | AC0003
+------------+----------+--------
I am pretty new to SQL and trying the below query but I dont think I am near to the correct solution at all ! Here is the query:
select startrange, endrange, id from table inner join (select 1 startRange, 3 endrange union all select 4 startRange, 6 endRange) r group by r.startRange, r.endRange;
It is giving the same id every-time and I am not able to come up with any other solution. How Can I get the required output?
Try this
SET #ct := 0;
select startrange,(startrange + 2) as endrange, seq_no from
(select (c.st - (select count(*) from <table_name>)) as startrange, c.* from
(select (#ct := #ct + 1) as st, b.* from <table_name> as b) c
having startrange mod 3 = 1) as cc;
sorry for formating.
I'm not completely sure what your trying to do but if you're trying to convert a table of ID's into ranges use a case when.
CASE WHEN startrange in(1,2,3) THEN 1
ELSE NULL
END as startrange,
CASE WHEN endrange in(1,2,3) THEN 3
ELSE NULL
END as endrange,
CASE WHEN ID in(1,2,3) THEN id
WHEN ID in(4,5,6) THEN id
ELSE id
END AS ID

Sql to find timediff between two rows based on ID

The subject of the question is not very explanatory, sorry for that.
Ya so the question follows:
I have a database structure as below where pk is primary key, id
is something which is multiple for many rows.
+------+------+---------------------+
| pk | id | value |
+------+------+---------------------+
| 99 | 1 | 2013-08-06 11:10:00 |
| 100 | 1 | 2013-08-06 11:15:00 |
| 101 | 1 | 2013-08-06 11:20:00 |
| 102 | 1 | 2013-08-06 11:25:00 |
| 103 | 2 | 2013-08-06 15:10:00 |
| 104 | 2 | 2013-08-06 15:15:00 |
| 105 | 2 | 2013-08-06 15:20:00 |
+------+------+---------------------+
What is really need to get is, value difference between first two rows (which is ordered by value) for each
group (where group is by id). So according to above structure I need
timediff(value100, value99) [ which is for id 1 group]
and timediff(value104, value103) [ which is for id 2 group]
i.e. value difference of time ordered by value for 1st two rows in each group.
One way i can think to do is by 3 self joins (or 3 sub queries) so as to find the
first two in 2 of them , and third query subtracting it. Any suggestions?
try this.. CTE is pretty powerfull!
WITH CTE AS (
SELECT
value, pk, id,
rnk = ROW_NUMBER() OVER ( PARTITION BY id order by id DESC)
, rownum = ROW_NUMBER() OVER (ORDER BY id, pk)
FROM test
)
SELECT
curr.rnk, prev.rnk, curr.rownum, prev.rownum, curr.pk, prev.pk, curr.id, prev.id, curr.value, prev.value, curr.value - prev.value
FROM CTE curr
INNER JOIN CTE prev on curr.rownum = prev.rownum -1 and curr.id = prev.id
and curr.rnk <=1
Looks a bit wierd... But you can try this way
SET #previous = 0;
SET #temp = 0;
SET #tempID = 0;
Above step may not be needed .. But just to make sure nothing goes wrong
SELECT pkid, id, diff, valtemp FROM (
SELECT IF(#previousID = id, #temp := #temp + 1, #temp := 1) occ, #previousID := id,
TIMEDIFF(`value`, #previous) diff, pk, id, `value`, #previous := `value`
FROM testtable) a WHERE occ = 2
Demo on sql fiddle

How to group subsequent rows (based on a criteria) and then count them [MySQL]?

Let's say I have such a table (ordered by date):
id | name | type | date
1 | A | 1 | 01-08-2012
2 | A | 2 | 01-08-2012
3 | B | 1 | 02-09-2012
4 | A | 1 | 01-10-2012
5 | A | 4 | 01-10-2012
6 | A | 5 | 02-10-2012
I want to group subsequent rows that have the same 'name' value and count them:
name | count
A | 2
B | 1
A | 3
I was thinking about writing a stored procedure and using cursors, but I was also wondering, if there's a simpler solution, for example using nested SELECTs, etc.
My question is very similar to: how to group array and count them, but that one concerns PHP.
To do that I used a couple of variables,
the table structure, I created my own just for testing and it's:
create table abc (id int, name varchar(20),type int);
insert into abc values
( 1 , 'A' , 1 ),
( 2 , 'A' , 2 ),
( 3 , 'B' , 1 ),
( 4 , 'A' , 1 ),
( 5 , 'A' , 4 ),
( 6 , 'A' , 5 )
the query ended being like this:
set #a:='';
set #counter:=1;
set #groupby:=0;
select *,count(REPEATED) from (select name,if(#a=name,#counter:=#counter+1,#counter:=1) as rep,if(#counter=1,#groupby:=#groupby+1,#groupby) as repeated,#a:=name type from abc) as t group by repeated
you can see it works in SQLFIDDLE if you have any question let me know.
In the SQLFIDDLE