I have the following details in MySQL as
user_id follow_user_id
1 2,3,3,3,3
5 1,2,3,3,3,3
6 1,2,3,3,3,3
i write the following code to get the unique code as follow:
SELECT LENGTH( follow_user_id ) - LENGTH( REPLACE( follow_user_id, ',', '' ) ) +1 AS no_of_follow FROM follow WHERE user_id =1;
But it provide the result:6
I need exactly unique rows: i.e:4
Apart from DB design questions you could use in PHP after fetching the row to $result:
count(array_unique(explode(",",$result["follow_user_id")));
$query="SELECT follow_user_id FROM follow WHERE user_id ='".$_POST['user_id']."' "; $query_run=mysql_query($query); $row= mysql_fetch_assoc($query_run);
$count= count(array_unique(explode(",",$row['follow_user_id'])));
$count;
This is better and faster ;)
count(array_flip(explode(",", $result["follow_user_id")));
Or doing it in SQL:-
SELECT COUNT(DISTINCT SUBSTRING_INDEX(SUBSTRING_INDEX(follow_user_id, ',', units.i + tens.i * 10), ',', -1) AS col1)
FROM sometable
CROSS JOIN (SELECT 0 i 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 i 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 user_id = 1
(copes with up to 100 comma separated values).
But this would be so much easier with a properly normalised database design
Related
Hello i have mysql table which named numbers like this;
ID
Number
1
3002
2
3004
2000
7545
When i need to insert a new data products table i have to find first number which is not on this table between(3000 to 35000). I mean i need to find first number between this numbers not on numbers table. How can i find it?
$statement = $con->prepare("SELECT * FROM numbers");
$statement->execute();
$result = $statement->fetchAll(PDO::FETCH_ASSOC);
foreach($result as $row)
{
$arr1[] = $row['numbers'];
}
$arr2 = range(3000,35000);
$missing_numbers = array_diff($arr2,$arr1);
print_r($missing_numbers);
i tried array_diff but i gives results with different keys. When i write $missing_numbers[0] i want to see first missing number.
If you just want the first missing number, it may be easier to read the rows in number order and check for the first one which isn't in the sequence you are after. So a query (with the start and end points as parameters) order by the number and a counter which is what it's expecting to get on each row...
$startPoint = 3000;
$endPoint = 35000;
$statement = $db->prepare("SELECT number
FROM numbers
WHERE number >= :start
and number <= :end
order by number");
$statement->execute([
'start' => $startPoint,
'end' => $endPoint
]);
$expected = $startPoint;
while ($row = $statement->fetch()) {
if ( $row['number'] != $expected ) {
echo "Missing=" . $expected;
break;
}
$expected++;
}
I think your solution will work only thing missing is reordering of the indexes which can be done by using the array_values() function. Update your last lines of code as -
$missing_numbers = array_values(array_diff($arr2,$arr1));
print_r($missing_numbers);
so on printing $missing_numbers[0] you should get the first missing number.
Easy, just need reset keys after array_diff:
...
$missing_numbers = array_values(missing_numbers);
print_r($missing_numbers);
IF you want do it only by using MySQL query and later get the result in PHP you need to do something like this :
Create temporray table with your example :
create table test123(id integer, Number varchar(100))
#insert into test123 (ID, Number) values (1, '3002');
#insert into test123 (ID, Number) values (2, '3004');
#insert into test123 (ID, Number) values (2000, '7545');
CREATE TEMPORARY TABLE WITH RANGE 3000 - 35000
CREATE TEMPORARY TABLE IF NOT EXISTS tableTest AS (
SELECT #row := #row + 1 AS row FROM
(select 0 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) t,
(select 0 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 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 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 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,
(SELECT #row:=3000) numbers WHERE #row < 35000
)
AND FINALLY you can just select numbers that's not inside your table with data
select * from tableTest t where t.row not in ( select Number from test123)
The output will be select all numbers as you wanted.
Mysql Table:
In My facility table is this
facility_name mbid date
yoga,aerobics,table tennis,tai chi, OM1111 2016-06-12
aerobics,tai chi, OM1111 2016-06-12
How to split row value one by one with mbid in mysql:
Facility_name mbid Number of count
yoga OM1111 1
aerobics OM1111 2
table tennis OM1111 1
tai chi OM1111 2
CREATE TABLE facility
(facility_name varchar(35), mbid varchar(6), date varchar(10))
;
INSERT INTO facility
(facility_name, mbid, date)
VALUES
('yoga,aerobics,table tennis,tai chi,', 'OM1111', '2016-06-12'),
('aerobics,tai chi,', 'OM1111', '2016-06-12')
;
Script :
Select T.VALUE,T.mbid,COUNT(T.VALUE)Cnt FROM (
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(t.facility_name, ',', n.n), ',', -1) value,mbid
FROM facility t CROSS JOIN
(
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
) n
WHERE n.n <= 1 + (LENGTH(t.facility_name) - LENGTH(REPLACE(t.facility_name, ',', ''))))T
WHERE T.VALUE <> ''
GROUP BY T.VALUE,T.mbid
ORDER BY T.value
How to pass the date function in where condition to get count of activity :
Select facility.mbid,membership.name,membership.organization,
membership.designation,membership.division, facility.VALUE `Facility Name`,
COUNT(facility.VALUE)`Number of Activite` FROM ( SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(facility.facility_name, ',', n.n), ',', -1) value,mbid FROM facility CROSS JOIN
(
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
) n
WHERE n.n <= 1 + (LENGTH(facility.facility_name) -LENGTH(REPLACE(facility.facility_name, ',', ''))))T
facility Inner Join membership ON facility.mbid=membership.mbid
where facility.date Between '2016-06-04' and '2016-06-07' &&
facility.VALUE <> ''
GROUP BY facility.VALUE,facility.mbid ORDER BY facility.value
You have a very poor database structure. You should have one row per mbid and facility_name. In fact, I have no idea why mbid and date are the same in the two rows.
If I assume that you have facility names in another table, then you can use:
select fn.facility_name, f.mbid, count(*)
from facility f join
facility_names fn
on find_in_set(fn.facility_name, f.facility) > 0
group by fn.facility_name, f.mbid;
I should emphasize, though, that although you can do a query like this, you really need to fix your data structure. Storing lists of values in a string is the wrong way to store data in a SQL database.
I need to concat multiple row column values into one column. I know I can use GROUP_CONCAT for that. But it does not fit my needs. This is my query:
SELECT
GROUP_CONCAT(twv.value ORDER BY twv.id ASC SEPARATOR ';') as needed_values
FROM table_with_values twv
WHERE twv.valuetype_id IN (9,12,13,15,17,29)
GROUP BY twv.person_id
The problem is that when a row with for example valuetype_id = 13 is not found, this value will of course not be concatenated.
How can i accomplish that in the case a person_id does not have a value for valuetype_id = 13 that '-' will be inserted in that part?
Thanks
#Giles
I tried your idea, and later changed it a bit. Tested the query below and it gives me 5 rows instead of the expected 6 (because i'm left joining??).
SELECT vid
FROM (SELECT 9 vid UNION SELECT 12 UNION SELECT 13 UNION SELECT 15 UNION SELECT 17 UNION SELECT 29) vids
LEFT JOIN sollicitant_profiel sp1 ON (sp1.vraag_id = vids.vid)
WHERE sp1.sollicitant_id = 1
Whereas this one does work and gives 6 rows as expected:
SELECT vids.vid, vids2.vid
FROM (SELECT 9 vid UNION SELECT 12 UNION SELECT 13 UNION SELECT 15 UNION SELECT 17 UNION SELECT 29) vids
LEFT JOIN (SELECT 9 vid UNION SELECT 12 UNION SELECT 13 UNION SELECT 15 UNION SELECT 17) vids2 ON (vids.vid = vids2.vid)
Something like this should work:
SELECT
GROUP_CONCAT(COALESCE(twv.value,'-') ORDER BY twv.id ASC SEPARATOR ';') as needed_values
FROM table_with_values twv
RIGHT JOIN (SELECT 9 vid UNION SELECT 12 UNION SELECT 13 UNION SELECT 15 UNION SELECT 17 UNION SELECT 29) vids
ON vids.vid = twv.valuetype_id
GROUP BY twv.person_id
Not having your values I am unable to test it. The "vids" sub-select may be better as a temp table.
you can use IF_NULL , it returns second parameter '-' when GROUP_CONCAT IS NULL.
SELECT
IF_NULL(GROUP_CONCAT(twv.value ORDER BY twv.id ASC SEPARATOR ';'),'-') as needed_values
FROM table_with_values twv
LEFT JOIN (SELECT 9 vid UNION SELECT 12 UNION SELECT 13 UNION SELECT 15 UNION SELECT 17 UNION SELECT 29) vids
ON vids.vid = twv.valuetype_id
GROUP BY twv.person_id
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I have a row with
(name1, name2, name3, name4)
AND another row with
(2, 3, 4, 5, 7)
I need to present that data in two columns, the name with the number in the same place like this:
NAMES | NUMBERS
--------------------
name1 2
name2 3
name3 4
name4 5
I tried with SUBSRTING_INDEX but I repaet the same number at first
I think in MySQL it might be done in a way similar to this:
CREATE TABLE t (names char(255), numbers char(255));
INSERT INTO t(names, numbers) VALUES('name1,name2,name3,name4', '2,3,5,7');
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(t.names, ',', idx), ',', -1),
SUBSTRING_INDEX(SUBSTRING_INDEX(t.numbers, ',', idx), ',', -1)
FROM t, (select 1 idx union all select 2 union all select 3 union all select 4) r
Here is complete sqlfiddle
Sure, subquery generating number sequence should be adjusted to your case. There are a number of examples on stackoverflow how to achieve this particular task.
Update:
Here is an example how to handle up to 10000 elements in a row.
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(t.names, ',', idx), ',', -1),
SUBSTRING_INDEX(SUBSTRING_INDEX(t.numbers, ',', idx), ',', -1)
FROM t,
(SELECT #row := #row + 1 AS idx FROM
(SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) n,
(SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) n2,
(SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) n3,
(SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) n4,
(SELECT #row:=0) n5
WHERE #row < (SELECT max(LENGTH(NAMES) - LENGTH(REPLACE(NAMES, ',', '')) + 1)
FROM t))r
Notice that to reduce amount of operations on strings we at first find maximum amount of elements in one row using a subquery.
I found the answer i used the function GROUP_CONCAT()
I am trying to create php script that generates 11,000,000 million unique ids in sequential order. However, I am trying to do it very quickly within 20 min it should generate these 11 million unique ids. Also, once it reaches 12,000,000 it should wrap around and start back at zero.
Here is what I have so far. This script would would only return one id at a time. I just added a loop to see how long it would take to generate the ids.
while(true){
try {
$this->getAdapter()->query('INSERT INTO generate_ids (assigned_id) SELECT (MAX(assigned_id)+1) FROM generate_ids');
$id = $this->getAdapter()->lastInsertId();
$sql = 'SELECT assigned_id FROM generate_ids WHERE id = $id';
$query = $this->getAdapter()->query($sql);
$result = $query->fetchAll();
//Live system would return id here
$assigned_id = $result[0]['assigned_id'];
} catch (Exception $e) {
//do nothing
}
if($count == 11000000){
die();
}
$count++;
}
}
If you create the following table:
CREATE TABLE sequence (
sequence_id BIGINT NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`sequence_id`)
)
Then issue these three queries one after the other:
INSERT INTO sequence () VALUES ();
DELETE FROM sequence WHERE sequence_id < LAST_INSERT_ID();
SELECT LAST_INSERT_ID() AS sequence;
The third query is guaranteed to return a unique sequence number. This guarantee holds even if you have dozens of different client programs connected to your database. That's the beauty of AUTO_INCREMENT.
Instead of just generating eleven million of these sequence numbers up front, you can use these SQL queries to get a unique sequence number whenever you need it.
If you must wrap around at sequence number 12 million you can use these queries instead.
INSERT INTO sequence () VALUES ();
DELETE FROM sequence WHERE sequence_id < LAST_INSERT_ID();
SELECT LAST_INSERT_ID() MOD 12000000 AS sequence;
The trick here is to use an auto-increment sequence number for uniqueness, but to also delete the rows in the table so it doesn't gobble up lots of space.
Note that you can also use the sequence number of LAST_INSERT_ID() for other purposes, like so for example.
INSERT INTO sequence () VALUES ();
DELETE FROM sequence WHERE sequence_id < LAST_INSERT_ID();
INSERT INTO user (userid, username, phone)
VALUES (LAST_INSERT_ID() MOD 12000000, 'Joe', '800-555-1212');
SELECT LAST_INSERT_ID() MOD 12000000 AS sequence;
If you need to insert all your ids at once (for some reason) the fastest approach would be to do it in pure SQL
insert into generate_ids (assigned_id)
select N
from
(
select a.N + b.N * 10 + c.N * 100 + d.N * 1000 + e.N * 10000 + f.N * 100000 + g.N * 1000000 + h.N * 10000000 + 1 as 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
,(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) c
,(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) d
,(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) e
,(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) f
,(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) g
,(select 0 as N union all select 1) h
order by N
) q
where N <= 11000000
It takes less than a minute to complete on my laptop.