I have a column in my database name location which have city name and country name in this format New york,America. I want to run a select query with the explode function like which we use in php to separate values like this
so that i can get comma , separated values
select explode(",",location) from address;
Also with the alias of city column holding New York and alias of country holding value of America. So that i can use them in my store procedure and insert this values in references table in the columns city and country
You can not really "explode" or split on all comma's, but you can split a string on any comma using SUBSTRING_INDEX.
SELECT SUBSTRING_INDEX('New york,America', ',', 1);
-> New york
Use Group concat
SELECT GROUP_CONCAT( location )
FROM `address`
CREATE FUNCTION strSplit(x varchar(255), delim varchar(12), pos int)
returns varchar(255)
return replace(substring(
substring_index(x, delim, pos+1),
length(substring_index(x, delim, pos)) + 1
), delim, '');
select strSplit("aaa,b,cc,d", ',', 1) as second;
> b
You can also select the row and store it as a string, and use the explode function to separate the values if you are intending to use the function itself.
Assuming that exploding will be to create N number of rows, then you can do it like this.
SET #completeString = "Hola,New york,America,!,";
SET #divider = ",";
WITH RECURSIVE strings(m) AS (
SELECT
#completeString
UNION ALL
SELECT
SUBSTRING(m, INSTR(m, #divider)+ 1)
FROM
strings
WHERE
INSTR(m, #divider)!= 0
)
SELECT
SUBSTRING_INDEX(m, #divider, 1) exploted_strings
FROM
strings;
That'll give you five rows, including the empty string
+----------------+
|exploted_strings|
+----------------+
| Hola |
| New york |
| America |
| ! |
| |
+----------------+
Or have it in a Procedure.
CREATE PROCEDURE explode(IN completeString TEXT, IN divider TEXT)
BEGIN
WITH RECURSIVE strings(m) AS (
SELECT
completeString
UNION ALL
SELECT
SUBSTRING(m, INSTR(m, divider)+ 1)
FROM
strings
WHERE
INSTR(m, divider)!= 0
)
SELECT
SUBSTRING_INDEX(m, divider, 1)
FROM strings;
END
And call it like
CALL explode ("Hola,New york,America,!,",",");
Related
I have a field COLORS (varchar(50)) in a my table SHIRTS that contains a comma delimited string such as 1,2,5,12,15,. Each number representing the available colors.
When running the query select * from shirts where colors like '%1%' to get all the red shirts (color=1), I also get the shirts whose color is grey (=12) and orange (=15).
How should I rewrite the query so that is selects ONLY the color 1 and not all colors containing the number 1?
The classic way would be to add commas to the left and right:
select * from shirts where CONCAT(',', colors, ',') like '%,1,%'
But find_in_set also works:
select * from shirts where find_in_set('1',colors) <> 0
FIND_IN_SET is your friend in this case
select * from shirts where FIND_IN_SET(1,colors)
Take a look at the FIND_IN_SET function for MySQL.
SELECT *
FROM shirts
WHERE FIND_IN_SET('1',colors) > 0
This will work for sure, and I actually tried it out:
lwdba#localhost (DB test) :: DROP TABLE IF EXISTS shirts;
Query OK, 0 rows affected (0.08 sec)
lwdba#localhost (DB test) :: CREATE TABLE shirts
-> (<BR>
-> id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
-> ticketnumber INT,
-> colors VARCHAR(30)
-> );<BR>
Query OK, 0 rows affected (0.19 sec)
lwdba#localhost (DB test) :: INSERT INTO shirts (ticketnumber,colors) VALUES
-> (32423,'1,2,5,12,15'),
-> (32424,'1,5,12,15,30'),
-> (32425,'2,5,11,15,28'),
-> (32426,'1,2,7,12,15'),
-> (32427,'2,4,8,12,15');
Query OK, 5 rows affected (0.06 sec)
Records: 5 Duplicates: 0 Warnings: 0
lwdba#localhost (DB test) :: SELECT * FROM shirts WHERE LOCATE(CONCAT(',', 1 ,','),CONCAT(',',colors,',')) > 0;
+----+--------------+--------------+
| id | ticketnumber | colors |
+----+--------------+--------------+
| 1 | 32423 | 1,2,5,12,15 |
| 2 | 32424 | 1,5,12,15,30 |
| 4 | 32426 | 1,2,7,12,15 |
+----+--------------+--------------+
3 rows in set (0.00 sec)
Give it a Try !!!
If the set of colors is more or less fixed, the most efficient and also most readable way would be to use string constants in your app and then use MySQL's SET type with FIND_IN_SET('red',colors) in your queries. When using the SET type with FIND_IN_SET, MySQL uses one integer to store all values and uses binary "and" operation to check for presence of values which is way more efficient than scanning a comma-separated string.
In SET('red','blue','green'), 'red' would be stored internally as 1, 'blue' would be stored internally as 2 and 'green' would be stored internally as 4. The value 'red,blue' would be stored as 3 (1|2) and 'red,green' as 5 (1|4).
select * from shirts where find_in_set('1',colors) <> 0
Works for me
If you're using MySQL, there is a method REGEXP that you can use...
http://dev.mysql.com/doc/refman/5.1/en/regexp.html#operator_regexp
So then you would use:
SELECT * FROM `shirts` WHERE `colors` REGEXP '\b1\b'
You should actually fix your database schema so that you have three tables:
shirt: shirt_id, shirt_name
color: color_id, color_name
shirtcolor: shirt_id, color_id
Then if you want to find all of the shirts that are red, you'd do a query like:
SELECT *
FROM shirt, color
WHERE color.color_name = 'red'
AND shirt.shirt_id = shirtcolor.shirt_id
AND color.color_id = shirtcolor.color_id
You can achieve this by following function.
Run following query to create function.
DELIMITER ||
CREATE FUNCTION `TOTAL_OCCURANCE`(`commastring` TEXT, `findme` VARCHAR(255)) RETURNS int(11)
NO SQL
-- SANI: First param is for comma separated string and 2nd for string to find.
return ROUND (
(
LENGTH(commastring)
- LENGTH( REPLACE ( commastring, findme, "") )
) / LENGTH(findme)
);
And call this function like this
msyql> select TOTAL_OCCURANCE('A,B,C,A,D,X,B,AB', 'A');
1. For MySQL:
SELECT FIND_IN_SET(5, columnname) AS result
FROM table
2.For Postgres SQL :
SELECT *
FROM TABLENAME f
WHERE 'searchvalue' = ANY (string_to_array(COLUMNNAME, ','))
Example
select *
from customer f
where '11' = ANY (string_to_array(customerids, ','))
All the answers are not really correct, try this:
select * from shirts where 1 IN (colors);
I have a field COLORS (varchar(50)) in a my table SHIRTS that contains a comma delimited string such as 1,2,5,12,15,. Each number representing the available colors.
When running the query select * from shirts where colors like '%1%' to get all the red shirts (color=1), I also get the shirts whose color is grey (=12) and orange (=15).
How should I rewrite the query so that is selects ONLY the color 1 and not all colors containing the number 1?
The classic way would be to add commas to the left and right:
select * from shirts where CONCAT(',', colors, ',') like '%,1,%'
But find_in_set also works:
select * from shirts where find_in_set('1',colors) <> 0
FIND_IN_SET is your friend in this case
select * from shirts where FIND_IN_SET(1,colors)
Take a look at the FIND_IN_SET function for MySQL.
SELECT *
FROM shirts
WHERE FIND_IN_SET('1',colors) > 0
This will work for sure, and I actually tried it out:
lwdba#localhost (DB test) :: DROP TABLE IF EXISTS shirts;
Query OK, 0 rows affected (0.08 sec)
lwdba#localhost (DB test) :: CREATE TABLE shirts
-> (<BR>
-> id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
-> ticketnumber INT,
-> colors VARCHAR(30)
-> );<BR>
Query OK, 0 rows affected (0.19 sec)
lwdba#localhost (DB test) :: INSERT INTO shirts (ticketnumber,colors) VALUES
-> (32423,'1,2,5,12,15'),
-> (32424,'1,5,12,15,30'),
-> (32425,'2,5,11,15,28'),
-> (32426,'1,2,7,12,15'),
-> (32427,'2,4,8,12,15');
Query OK, 5 rows affected (0.06 sec)
Records: 5 Duplicates: 0 Warnings: 0
lwdba#localhost (DB test) :: SELECT * FROM shirts WHERE LOCATE(CONCAT(',', 1 ,','),CONCAT(',',colors,',')) > 0;
+----+--------------+--------------+
| id | ticketnumber | colors |
+----+--------------+--------------+
| 1 | 32423 | 1,2,5,12,15 |
| 2 | 32424 | 1,5,12,15,30 |
| 4 | 32426 | 1,2,7,12,15 |
+----+--------------+--------------+
3 rows in set (0.00 sec)
Give it a Try !!!
If the set of colors is more or less fixed, the most efficient and also most readable way would be to use string constants in your app and then use MySQL's SET type with FIND_IN_SET('red',colors) in your queries. When using the SET type with FIND_IN_SET, MySQL uses one integer to store all values and uses binary "and" operation to check for presence of values which is way more efficient than scanning a comma-separated string.
In SET('red','blue','green'), 'red' would be stored internally as 1, 'blue' would be stored internally as 2 and 'green' would be stored internally as 4. The value 'red,blue' would be stored as 3 (1|2) and 'red,green' as 5 (1|4).
select * from shirts where find_in_set('1',colors) <> 0
Works for me
If you're using MySQL, there is a method REGEXP that you can use...
http://dev.mysql.com/doc/refman/5.1/en/regexp.html#operator_regexp
So then you would use:
SELECT * FROM `shirts` WHERE `colors` REGEXP '\b1\b'
You should actually fix your database schema so that you have three tables:
shirt: shirt_id, shirt_name
color: color_id, color_name
shirtcolor: shirt_id, color_id
Then if you want to find all of the shirts that are red, you'd do a query like:
SELECT *
FROM shirt, color
WHERE color.color_name = 'red'
AND shirt.shirt_id = shirtcolor.shirt_id
AND color.color_id = shirtcolor.color_id
You can achieve this by following function.
Run following query to create function.
DELIMITER ||
CREATE FUNCTION `TOTAL_OCCURANCE`(`commastring` TEXT, `findme` VARCHAR(255)) RETURNS int(11)
NO SQL
-- SANI: First param is for comma separated string and 2nd for string to find.
return ROUND (
(
LENGTH(commastring)
- LENGTH( REPLACE ( commastring, findme, "") )
) / LENGTH(findme)
);
And call this function like this
msyql> select TOTAL_OCCURANCE('A,B,C,A,D,X,B,AB', 'A');
1. For MySQL:
SELECT FIND_IN_SET(5, columnname) AS result
FROM table
2.For Postgres SQL :
SELECT *
FROM TABLENAME f
WHERE 'searchvalue' = ANY (string_to_array(COLUMNNAME, ','))
Example
select *
from customer f
where '11' = ANY (string_to_array(customerids, ','))
All the answers are not really correct, try this:
select * from shirts where 1 IN (colors);
I have a table like this:
TITLE | DESCRIPTION
------------------------------------------------
test1 | value blah blah value
test2 | value test
test3 | test test test
test4 | valuevaluevaluevaluevalue
I am trying to figure out how to return the number of times a string occurs in each of the DESCRIPTION's.
So, if I want to count the number of times 'value' appears, the sql statement will return this:
TITLE | DESCRIPTION | COUNT
------------------------------------------------------------
test1 | value blah blah value | 2
test2 | value test | 1
test3 | test test test | 0
test4 | valuevaluevaluevaluevalue | 5
Is there any way to do this? I do not want to use php at all, just mysql.
This should do the trick:
SELECT
title,
description,
ROUND (
(
LENGTH(description)
- LENGTH( REPLACE ( description, "value", "") )
) / LENGTH("value")
) AS count
FROM <table>
A little bit simpler and more effective variation of #yannis solution:
SELECT
title,
description,
CHAR_LENGTH(description) - CHAR_LENGTH( REPLACE ( description, 'value', '1234') )
AS `count`
FROM <table>
The difference is that I replace the "value" string with a 1-char shorter string ("1234" in this case). This way you don't need to divide and round to get an integer value.
Generalized version (works for every needle string):
SET #needle = 'value';
SELECT
description,
CHAR_LENGTH(description) - CHAR_LENGTH(REPLACE(description, #needle, SPACE(LENGTH(#needle)-1)))
AS `count`
FROM <table>
try this:
select TITLE,
(length(DESCRIPTION )-length(replace(DESCRIPTION ,'value','')))/5 as COUNT
FROM <table>
SQL Fiddle Demo
In SQL SERVER, this is the answer
Declare #t table(TITLE VARCHAR(100), DESCRIPTION VARCHAR(100))
INSERT INTO #t SELECT 'test1', 'value blah blah value'
INSERT INTO #t SELECT 'test2','value test'
INSERT INTO #t SELECT 'test3','test test test'
INSERT INTO #t SELECT 'test4','valuevaluevaluevaluevalue'
SELECT TITLE,DESCRIPTION,Count = (LEN(DESCRIPTION) - LEN(REPLACE(DESCRIPTION, 'value', '')))/LEN('value')
FROM #t
Result
TITLE DESCRIPTION Count
test1 value blah blah value 2
test2 value test 1
test3 test test test 0
test4 valuevaluevaluevaluevalue 5
I don't have MySQL install, but goggled to find the Equivalent of LEN is LENGTH while REPLACE is same.
So the equivalent query in MySql should be
SELECT TITLE,DESCRIPTION, (LENGTH(DESCRIPTION) - LENGTH(REPLACE(DESCRIPTION, 'value', '')))/LENGTH('value') AS Count
FROM <yourTable>
Please let me know if it worked for you in MySql also.
Here is a function that will do that.
CREATE FUNCTION count_str(haystack TEXT, needle VARCHAR(32))
RETURNS INTEGER DETERMINISTIC
BEGIN
RETURN ROUND((CHAR_LENGTH(haystack) - CHAR_LENGTH(REPLACE(haystack, needle, ""))) / CHAR_LENGTH(needle));
END;
This is the mysql function using the space technique (tested with mysql 5.0 + 5.5):
CREATE FUNCTION count_str( haystack TEXT, needle VARCHAR(32))
RETURNS INTEGER DETERMINISTIC
RETURN LENGTH(haystack) - LENGTH( REPLACE ( haystack, needle, space(char_length(needle)-1)) );
SELECT
id,
jsondata,
ROUND (
(
LENGTH(jsondata)
- LENGTH( REPLACE ( jsondata, "sonal", "") )
) / LENGTH("sonal")
)
+
ROUND (
(
LENGTH(jsondata)
- LENGTH( REPLACE ( jsondata, "khunt", "") )
) / LENGTH("khunt")
)
AS count1 FROM test ORDER BY count1 DESC LIMIT 0, 2
Thanks Yannis, your solution worked for me and here I'm sharing same solution for multiple keywords with order and limit.
In most cases, these functions are LENGTH and REPLACE, respectively (SQL Server users will use the built-in function LEN rather than LENGTH):
Example, count num of comma in the string "10,CLARK,MANAGER"
select (length('10,CLARK,MANAGER')-
length(replace('10,CLARK,MANAGER',',','')))/length(',')
as cnt from t1
I have an array I would like to use to populate a pgsql table using pg_copy_from. But I get the following error when I don't give it information for my serial index column.
ERROR: there is data for a column index
How can I force pg_copy_from to ignore my index column and just let it increment independently. Since it takes comma-separated values I tried doing sometime like this to pass it a blank string in index's position:
array_walk($logs, function(&$record) {
"'', " . $record;
});
But it did not work. I also tried making a table where index was the second column, and I didn't pass a second value, but I received the same error. Is there an option for this?
DISCLAIMER. I'm not a PHP developer, but it sounds like you probably need to just insert the word DEFAULT into your array for your "index" column (and I'm assuming this in your primary key and it's got a sequencer). For example:
create temp table foobar(id serial, foo text);
insert into foobar values (DEFAULT, 'hello');
insert into foobar values (DEFAULT, 'world');
select * from foobar;
+----+-------+
| id | foo |
+----+-------+
| 1 | hello |
| 2 | world |
+----+-------+
(2 rows)
pg_copy_from doesn't allow you to exclude some columns. A combination of pg_query and pg_put_line does allow this because of your own COPY statement:
<?php
$conn = pg_pconnect("dbname=foo");
pg_query($conn, "create table bar (a serial, b char(16), d float8)"); // just an example
pg_query($conn, "copy bar(b, c) from stdin"); // only columns b and c !
pg_put_line($conn, "hello world\t4.5\n");
pg_put_line($conn, "goodbye world\t7.11\n");
pg_put_line($conn, "\\.\n");
pg_end_copy($conn);
?>
Trying to understand LEFT and LOCATE with mysql to help me process a string
I have text that contains a bunch of data and within it is
street_num="9716", street_name=
I need to extract just the street num
so I was trying to do
SELECT LEFT( newdata, LOCATE( 'street_name=', 'newdata' ) )
FROM `uploadTracker`
WHERE `type` =0
in that example I would like it to return 9716
In situations like this function SUBSTRING_INDEX() becomes very handy
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(newdata, 'street_num="', -1), '"', 1) street_num
FROM uploadTracker
WHERE type = 0
Output:
| STREET_NUM |
|------------|
| 9716 |
Here is SQLFiddle demo