SQL row column sum with spaces between numbers - mysql

mysql table:
table_results:
id results
1 1 0 1 2 4 5
2 5 4 2 6
3 7 2 8 2 4
I'm creating a Yii gridview I need to
SELECT SUM(results) AS results2 FROM table_results WHERE id = 1:
for example I have to sum first row: 1+0+1+2+4+5 and make as results2 which = 15.
How to do that just in sql?

There is no need for dynamic SQL. You can use:
SqlFiddleDemo
SELECT sub.id, SUM(sub.val) AS `sum`
FROM
(
SELECT id, SUBSTRING_INDEX(SUBSTRING_INDEX(t.results, ' ', n.n), ' ', -1) AS val
FROM table_results 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
) n
WHERE n.n <= 1 + (LENGTH(t.results) - LENGTH(REPLACE(t.results, ' ', '')))
) sub
-- WHERE sub.id = 1
GROUP BY sub.id

One way to do this is using dynamic SQL. So, entirely within MySQL:
declare #sql varchar(2000);
select #sql = concat('select ', replace(results, ' ', '+'))
from table_results tr
where id = 1;
prepare s from #sql;
execute s;
deallocate prepare s;
As a note: Just because I answered the question does not mean that I condone the data structure.

Related

Fetching Only Unique Results From Sql Database

Database Table
ID Post Tags
1 Range rover range-rover,cars
2 Lamborghini lamborghini,cars
3 Kawasaki kawasaki,bikes
4 Yamaha R1 yamaha,r1,bikes
I Want to Remove Duplicate Values from Result sql
What i Get When i fetch tags (tags are in ,) from Database
SELECT Tags from posts;
Resut:
range-rover,cars lamborghini,cars kawasaki,bikes yamaha,r1,bikes
What I Need is not to show same result again.
range-rover,cars lamborghini kawasaki,bikes yamaha,r1
You can split your text using tally table and SUBSTRING_INDEX:
SELECT DISTINCT SUBSTRING_INDEX(SUBSTRING_INDEX(t.tags, ',', n.n), ',', -1) AS val
FROM posts 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
) n
WHERE n.n <= 1 + (LENGTH(t.tags) - LENGTH(REPLACE(t.tags, ',', '')))
SqlFiddleDemo
If you need one row add GROUP_CONCAT:
SELECT GROUP_CONCAT(DISTINCT SUBSTRING_INDEX(SUBSTRING_INDEX(t.tags, ',', n.n), ',', -1)) AS val
...
SqlFiddleDemo2

How to select only particular word start with # from sentence mysql query

let's explain briefly
this is very new topic, I want to fetch only particular word start with # from sentence for example
i have sentence like
Hi Majjx Uxud Xhhxhd Hx Dhx #hdhd Jdhhdhshhfd Hxhhd #bhd Hxhd Hxhhd Dhhdh www.myinnos.in Hdhd Xfhhxhd Xhhdh Xhx 9560233669 ndhdh Hxhhdh Dhh
from above sentence I have to fetch #hdhd
got a solution for my question, now I want to count and show the repeated words as count
select val from(
select (substring_index(substring_index(a, ' ', n.n), ' ', -1)) val
from (select id, message as a from filmbooknewsfeed) t
cross join(
select a.n + b.n * 10 + 1 n
from
(select 0 as n 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
) a,
(select 0 as n 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
) b
order by n
) n
where n.n <= 1 + (length(t.a) - length(replace(t.a, ' ', '')))
order by val asc
)x where val like '#%'
As I said, you need to convert the sentence into rows. Just in case, if in sentence you have more than 1 words start with #.
select val from(
select (substring_index(substring_index(a, ' ', n.n), ' ', -1)) val
from (
select 'Hi Majjx Uxud Xhhxhd Hx Dhx #hdhd Jdhhdhshhfd Hxhhd #bhd Hxhd Hxhhd Dhhdh www.myinnos.in Hdhd Xfhhxhd Xhhdh Xhx 9560233669 ndhdh Hxhhdh Dhh' as a
) t
cross join(
select a.n + b.n * 10 + 1 n
from
(select 0 as n 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
) a,
(select 0 as n 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
) b
order by n
) n
where n.n <= 1 + (length(t.a) - length(replace(t.a, ' ', '')))
order by val asc
)x where val like '#%'
Will give you #hdhd. even if you has more than 1 # in the sentence. This would give you correct result.
edit
If you want to group by result and sort by most occurence words like twitter tranding topic, modify your query like this (as query on the question)
select val,count(val) as cnt from(
select (substring_index(substring_index(a, ' ', n.n), ' ', -1)) val
from (select id, message as a from filmbooknewsfeed) t
cross join(
select a.n + b.n * 10 + 1 n
from
(select 0 as n 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
) a,
(select 0 as n 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
) b
order by n
) n
where n.n <= 1 + (length(t.a) - length(replace(t.a, ' ', '')))
order by val asc
)x where val like '#%'
group by val
order by cnt desc
You can do this using substring_index():
select substring_index(substring_index(substring_index(sentence, '#', 2), '#', -1), ' ', 1)

How can I update a column with a value from a list of values for a set of records

I do an update in a table row by row:
UPDATE table
SET col = $value
WHERE id = $id
Now if I update e.g. 10000 records each record gets the $value but it does not really matter which $id gets which $value. The only requirement I have is that all the records I am updating end up with a $value.
So how could I convert this update to something like
UPDATE table
SET col ?????? what here from a $value_list???
WHERE id IN ($id_list)
I.e. pass the list ids and somehow the values and that range of ids get a value
Let's assume you've got two comma separated lists of your ids and your values with the same count of items. Then you could do your update with statements like those:
-- the list of the ids
SET #ids = '2,4,5,6';
-- the list of the values
SET #vals = '17, 73,55, 12';
UPDATE yourtable
INNER JOIN (
SELECT
SUBSTRING_INDEX(SUBSTRING_INDEX(t.ids, ',', n.n), ',', -1) id,
SUBSTRING_INDEX(SUBSTRING_INDEX(t.vals, ',', n.n), ',', -1) val
FROM (SELECT #ids as ids, #vals as vals) t
CROSS JOIN (
-- build for up to 1000 separated values
SELECT
1 + a.N + b.N * 10 + c.N * 100 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
ORDER BY n
) n
WHERE n <= (1 + LENGTH(t.ids) - LENGTH(REPLACE(t.ids, ',', '')))
) t1
ON
yourtable.id = t1.id
SET
yourtable.val = t1.val;
Explanation
The inner series of UNIONs builds a table with the numbers from 1 to 1000. You should be able to expand this mechanism to your needs:
-- build for up to 1000 separated values
SELECT
a.N + b.N * 10 + c.N * 100 + 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
ORDER BY n
We use this numbers to get the items out of our lists with the nested SUBSTRING_INDEX call
SUBSTRING_INDEX(SUBSTRING_INDEX(t.ids, ',', n.n), ',', -1) id,
SUBSTRING_INDEX(SUBSTRING_INDEX(t.vals, ',', n.n), ',', -1) val
The WHERE clause get the number of items in (ok only one of the two) lists:
WHERE n <= (1 + LENGTH(t.ids) - LENGTH(REPLACE(t.ids, ',', '')))
Because we've got one occurence of the separator less, we add 1 to the difference in length of the list with the separator and the length of the list without all occurrences of the separator.
Then we do the UPDATE with a JOIN operation on the id values in the outer UPDATE statement.
See it working in this fiddle.
Believe me: This is much faster than agonizing row-by-row update.

Rewrite to not include subquery in FROM?

A great fellow helped me with developing the following statement. However, in mySQL - I cannot save a view with a subquery in the FROM clause. Any suggestions o nhow to rewrite this so that it can be saved into a mySQL server?
SELECT t.idPatternMetadata, SUBSTRING_INDEX(SUBSTRING_INDEX(t.sKeywords, ',', n.n), ',', -1) color , count(*) as counts
FROM tblPatternMetadata 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.sKeywords) - LENGTH(REPLACE(t.sKeywords, ',', '')))
group by color
THANKS in advance!
One option is to create a table that contains the 100 integer values, and reference that table in the query.
CREATE TABLE n (n INT UNSIGNED PRIMARY KEY);
INSERT INTO n (n)
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
CROSS
JOIN ( 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 1;
Then rewrite your query to reference the table in place of the inline view:
SELECT t.idPatternMetadata, SUBSTRING_INDEX(SUBSTRING_INDEX(t.sKeywords, ',', n.n), ',', -1) AS color
, count(*) AS counts
FROM tblPatternMetadata t
JOIN n
ON n.n <= 1 + (LENGTH(t.sKeywords) - LENGTH(REPLACE(t.sKeywords, ',', '')))
GROUP BY color

Split mySQL column into many

Ive got a MySQL column that has a set of number that are separated by spaces. There is about 330 spaces..... and they are not all in the same place ( for each set)
Is there a way I can do this automatically, like via a query?
Or is this possible in Microsoft SQL?
Edit 1: I'm afraid I haven't really tried anything, - not to sure what to do.
Here is an example of one of the sets of numbers
3 10 13 18 0 0 175 215 177 173 213 203 592 272 0 175 215 177 173 215 177 172 208 203 592
It's very repetitive.
You can generate a list of numbers, then use those numbers cross joined against your data with SUBSTRING_INDEX to get the individual fields.
Something like this:-
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(SomeField, ' ', aNum + 1), ' ', -1)
FROM SomeTable
CROSS JOIN
(
SELECT Units.aCnt + Tens.aCnt * 10 + Hundreds.aCnt * 100 AS aNum
FROM
(SELECT 0 AS aCnt 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,
(SELECT 0 AS aCnt 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,
(SELECT 0 AS aCnt 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) Hundreds
) Sub1
WHERE LENGTH(SomeField) - LENGTH(REPLACE(SomeField, ' ', '')) >= aNum
SQL fiddle here:-
http://www.sqlfiddle.com/#!2/7c43a/4
Then find the person who designed the database table and explain to them about database design / normalisation / indexes.
EDIT - A way that can (just about) do this select, coping with the number of cols. It should return NULL for any col that doesn't exist for that row. Probably best used in a MySQL stored proc. It calculates the max number of cols and then generates some dynamic SQL to get those cols.
SET #sql = NULL;
SET SESSION group_concat_max_len = 1000000;
SELECT GROUP_CONCAT(aField ORDER BY aNum)
INTO #sql
FROM
(
SELECT (Units.aCnt + Tens.aCnt * 10 + Hundreds.aCnt * 100) AS aNum, CONCAT("IF(LENGTH(SomeField) - LENGTH(REPLACE(SomeField, ' ', '')) >= ", (Units.aCnt + Tens.aCnt * 10 + Hundreds.aCnt * 100), ", SUBSTRING_INDEX(SUBSTRING_INDEX(SomeField, ' ', ", (Units.aCnt + Tens.aCnt * 10 + Hundreds.aCnt * 100 + 1),"), ' ', -1), NULL) AS col",(Units.aCnt + Tens.aCnt * 10 + Hundreds.aCnt * 100)) AS aField
FROM (SELECT MAX(LENGTH(SomeField) - LENGTH(REPLACE(SomeField, ' ', ''))) AS MaxDelim FROM SomeTable) Sub1,
(SELECT 0 AS aCnt 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,
(SELECT 0 AS aCnt 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,
(SELECT 0 AS aCnt 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) Hundreds
WHERE Units.aCnt + Tens.aCnt * 10 + Hundreds.aCnt * 100 <= Sub1.MaxDelim
) Sub2;
SET #sql = CONCAT('SELECT ', #sql,
' FROM SomeTable
');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SQL fiddle for this:-
http://www.sqlfiddle.com/#!2/a28ab2/2