MySQL combine strings from many rows like SUM for int - mysql

I'm searching function which it's working like sum.
For simple I have 4 records in table:
id => 1
text => abc
id => 2
text => def
id => 3
text => ghi
id=> 4
text => jkm
When I used SUM() for ids my result is 10, so I would like to find another function for combine texts and I want to to have "abcdefghijkm" or, is it possible, "abc.def.ghi.jkm".
I'm trying with FOR XML PATH() but it isn't working with MySQL (I can't use this... function?). Also CONCAT() isn't working too.

Use GROUP_CONCAT() function:
SELECT SUM(id), GROUP_CONCAT(text SEPARATOR '.') FROM t

Related

MySQL swap numbers for letters in field

If I take a value of 12345 from MySQL and I want to display that at the front end as Mo Tu We Th Fr, how can I do that allowing for all possible combinations?
I could write a case statement but there are going to be many hundreds of combinations to cover all possible values.
The value will be anything from 1 to 7 characters long using between digits between 1 and 7 and could be in any order so 3417 should read We Th Mo Su whilst 645 should read Sa Th Fr and so on. I cannot do this in the application so have to try and figure out how to do it in MySQL. These are stored in MySQL as a varchar in a single column.
Can I use replace multiple times in the same select so something like:
REPLACE(REPLACE(REPLACE(field, '1', 'Mo '), '2', 'Tu'), '3', 'We')
or is there another way?
You can create a helper table that contains 2 columns :
1, su
2, mo
3, ...
then just join the day number to get the second column of the helper table.
If all you want to do is display this in a fronend, you can have a "dictionary" to translate the values.
Lets say for example you have a Table in the structure
tl_days
__________
id | alias
And we have some data such as
id: 1, alias : Mon
id: 2, alias : Tue
We can run a simple query to check the id against an array of numbers.
SELECT alias FROM 'tl_days' WHERE id in (1,2,3,4);
Will return the days as your abbreviations.
You should not write replace for all the values if there are multiple of them, Instead create a mapping table 1|su,2|mo ..., Then use join to fetch the 'su','mo' values from the mapping table
First you would need to ensure that the table schema data matches. If changing from numeric value to text value is acceptable.
Update table_name set column_name =
(
CASE
when column_name = 1 then 'Mo'
when column_name = 2 then 'Tu'
when column_name = 3 then 'We'
when column_name = 4 then 'Th'
when column_name = 5 then 'Fr'
End
);
Here is an SQL FIDDLE displaying such a change.

How to search from comma separated string in comma separated column mysql

I am working on a project where I have to code for job filters.
In this when I filters for salaries it sends salary id's in array like:
job_salary = array(
[0]=>3,
[1]=>4,
[2]=>5,
[3]=>6,
[4]=>7,
[5]=>8
)
and job in my jobs table contains multiple salaries using comma string.
id salary_ids
1 2,4,6
2 1,3,5
3 4,5
4 9,1
So if i search for value 3, and 5 in array form like
job_salary = array(
[0]=>3,
[1]=>5
);
It should return me the second and third row because these rows contain value 3 and 5.
Use it like below let me know if it works
$values=array("1","2","3");
foreach($values as $val)
{
$query="Select * from table_name where FIND_IN_SET('".$val."',column_name)";
$result=mysql_query($query);
$data=mysql_fetch_array($result);
$dbval[]=$data['column_name'];
}
print_r($dbval);
please try again like this
1).For Postgres MySQL :
SELECT FIND_IN_SET(5,userid) as result FROM department
2).For Postgres SQL :
select *
from TABLENAME f
where 'searchvalue' = ANY (string_to_array(COLOUMNNAME,','))
Example
select *
from customer f
where '11' = ANY (string_to_array(customerids,','))

MYSQL - Find rows, where part of search string matches part of value in column

I wasn't able to find this anywhere, here's my problem:
I have a string like '1 2 3 4 5' and then I have a mysql table that has a column, let's call it numbers, that look like this:
numbers
1 2 6 8 9 14
3
1 5 3 6 9
7 8 9 23 44
10
I am trying to find the easiest way (hopefully in a single query) to find the rows, where any of the numbers in my search string (1 or 2 or 3 or 4 or 5) is contained in the numbers column. In the give example I am looking for rows with 1,2 and 3 (since they share numbers with my search string).
I am trying to do this with a single query and no loops.
Thanks!
The best solution would be to get rid of the column containing a list of values, and use a schema where each value is in its own row. Then you can use WHERE number IN (1, 2, 3, 4, 5) and join this with the table containing the rest of the data.
But if you can't change the schema, you can use a regular expression.
SELECT *
FROM yourTable
WHERE numbers REGEXP '[[:<:]](1|2|3|4|5)[[:<:]]'
[[:<:]] and [[:<:]] match the beginning and end of words.
Note that this type of search will be very slow if the table is large, because it's not feasible to index it.
Here is a start point (split string function) : http://blog.fedecarg.com/2009/02/22/mysql-split-string-function/ := SplitString(string,delimiter,position)
Create a function so it converts a string to an array := stringSplitted(string,delimiter)
Create a function so it compares two arrays :=arrayIntersect(array1, array2)
SELECT numbers
FROM table
WHERE arrayIntersect(#argument, numbers)
Two function definitions with loops and one single query without any loop
SELECT * FROM MyTable WHERE (numbers LIKE '%1%' OR numbers LIKE '%2%')
or you can also use REGEX something like this
SELECT * FROM events WHERE id REGEXP '5587$'

MySQL fetching rows from 2 tables (not relational) with LEFT JOIN

I have the following 2 tables
table_article:
id subject tags
---------------------
1 subject-1 2,4,5
2 subject-2 3,5
3 subject-3 1,2
4 subject-4 2,3,4
5 subject-5 3
table_tags:
id tag_name
---------------------
1 php
2 jQuery
3 css
4 mysql
5 java
and I'm trying to get results like
id => 1, subject => subject-1, tag_names => jQuery,mysql,java
id => 2, subject => subject-2, tag_names => css,java
id => 3, subject => subject-3, tag_names => php,jQuery
Here is my current attempt, which returns ONLY the first tag (e.g. 2 instead of 2,4,5 for row 1)
1 SELECT
2 table_article.id,
3 table_article.subject,
4 GROUP_CONCAT(table_tags.tag_name) AS tag_names
5 FROM
6 table_article
7 LEFT JOIN
8 table_tags
9 ON
10 (table_tags.tag_id IN (table_article.tags))
11 GROUP BY
12 table_article.id
13 LIMIT
14 3
and the results are
id => 1, subject => subject-1, tag_names => jquery
id => 2, subject => subject-2, tag_names => css
id => 3, subject => subject-3, tag_names => php
The problem occurs on line 10 -> IN (table_article.tags).
I just can't figure out how could I solve this problem, can anyone help please?
You can't use a string that happens to contain commas as a list of discrete values.
In other words this:
ON table_tags.tag_id IN (2,4,5)
Is not the same as this:
ON table_tags.tag_id IN ('2,4,5')
The numeric value of a string like '2,4,5' is the initial numeric portion, and the remainder after the first non-numeric character is ignored. So the string '2,4,5' has a numeric value of 2. It won't be an error, but it won't get you what you intended, which is a match against any of the values in the comma-separated list.
MySQL has a built-in function FIND_IN_SET() which does understand strings that contain comma-separated values. The function returns the position of the matching value, or 0 if no match was found.
ON FIND_IN_SET(table_tags.tag_id, '2,4,5') > 0
But this cannot use an index and it forces you to run a table-scan which is going to kill your performance. To be clear, I don't recommend using this function in a join condition.
The answer is: Don't store tags in a comma-separated list. See my answer for Is storing a comma separated list in a database column really that bad?
Store one tag per row in a separate table, as #Martin Lyne suggests. That way you can look for the right tag with = and you can even index the column for much better performance.
I've not seen an IN in a ON before (not saying it's not valid) but I would do ON table_tags.tag_id = table_article.tags)
So you end up with multiple rows
subject-1, query
subject-1, css
subject 2, query
then the GROUP BY would compress the table and the GROUP_CONCAT gets all the missing tags.
Well, I would use IN in this situation, it won't work, replace it with FIND_IN_SET(table_tags.tag_id, table_article.tags) > 0 and you'll be fine. Though you really should normalize this.
As other said, this is not a good design.
Instead, you could change your table design this way:
table_article
id
subject
article_tag
article_id
tag_id
table_tags
id
tag_name
Life would be much easier this way :-)

MySQL Inner Query with a Where and Group by conditions in cakephp

i am having a table named Reports with
id report_id user_id
1 1 5
2 1 5
3 1 5
4 2 5
5 2 5
6 3 6
7 3 6
8 4 1
9 4 1
10 4 1
i am trying to write a Query such that user_id = 5 and to find how many reports he has created.(Answer should be of 2 )
i have a Wrote a Mysql Query as
select count(distinct report_id) from Reports where user_id=5
i m trying the same MYSQl sub Query inside the Foreach users loop where my 5 is from $user['User']['id'];
how to write the MYSQL Query above inside this for loop in cakephp Framework....
foreach($users as & $user):
echo "User id ".$user['User']['id'];
$user['User']['report_count'] = $this->Report->find('count',
array('conditions'=>array('Report.user_id'=>$user['User']['id'])));
endforeach;
$this->set('users', $users);
Please suggest me.......HOw to write the above Mysql Query in cakephp
You want to use the following functions GROUP BY and COUNT
Your query could look somewhat like this
select count(distinct report_id) from Reports where user_id=5
If this is a list of users you are showing in your application... you could significantly reduce the number of queries you are running.
eg. for 100 users you will be running 100 queries instead you can run a single single query to extract the user_id and count of reports by each user
select count(distinct report_id) as count,user_id from Reports where user_id IN (1,2) GROUP BY user_id;
OR if you want to run seperate queries for each user
select count(distinct report_id) as count,user_id from Report where user_id=5;
Try this:
$user['User']['report_count'] = $this->Report->find('count',
array( 'conditions' => array('Report.user_id' => $user['User']['id']),
'fields' => 'DISTINCT Report.report_id'
)
);
It should fetch all distinct report_ids for a given user_id, then count them. Basically, it should run the query:
SELECT DISTINCT report_id FROM Reports WHERE user_id=$user['User']['id']
(after substituting the value of $user['User']['id']), then count the number of rows in the result. Caveat: I don't use CakePHP in real life, I just read the documentation; your mileage may vary. As halocursed mentions, running a single SQL query on your own would be more efficient than calling find(...) for each user ID. You could also try:
$report_counts = $this->Report->find('list',
array( 'conditions' => array('Report.user_id' => array_map(create_function('$user', 'return $user["User"]["id"];'), $users)),
'group' => array('Report.user_id'),
'fields' => array('Report.user_id', 'COUNT(DISTINCT Report.report_id) AS report_count')
)
);
foreach ($users as &$user) {
$user['User']['report_count'] = $report_counts[$user['User']['id']];
}
However, I don't know if CakePHP will accept aggregate functions in the 'fields' parameter, and I don't know as though find('list', ...) will pick Report.user_id as the array index. If you're having problems with the latter, you could switch to a [find('all', ...)][3] call and loop over $report_counts rather than $users. I didn't take this approach because I don't know the structure of $users, such as how it's indexed.