MySQL: Using variable on a WHERE IN clause - mysql

I'm becoming mad trying to use an "array" of values obtained from a GROUP_CONCAT into a WHERE IN statement, when GROUP_CONCAT only takes one "id" it works ok but when it takes more it doesn't.
As it follows:
START TRANSACTION;
DECLARE #coupon_ids VARCHAR(MAX);
-- Take one or more ids
SET #coupon_ids:=(SELECT IFNULL( (SELECT GROUP_CONCAT(coupon_id) FROM some_table WHERE order_id=(SELECT entity_id FROM sales_order WHERE increment_id=310033638) GROUP BY order_id), (SELECT coupon_id FROM some_table WHERE coupon_id=310033638)));
SELECT #coupon_ids;
INSERT INTO some_table_gift VALUES (NULL,TRIM('whatever'),'','');
SET #lastid:=LAST_INSERT_ID();
-- Here if #coupon_ids is just one id, like 123 it works, if it is a list of them like 123,234,254 it doesn't works
UPDATE some_table SET owner_id=#lastid,is_gift=1 WHERE coupon_id IN (#coupon_ids);
COMMIT;
-- Same here
SELECT coupon_id,owner_id,is_gift FROM some_table WHERE coupon_id IN (#coupon_ids);
Does anyone know how to work with this?
Thanks!

What's your filed type for coupon_id, if it is not any number type than it will not work.
One way you can add quote (single quote) for each result in GROUP_CONCAT Write
GROUP_CONCAT(coupon_id SEPARATOR '","')
remove SELECT #coupon_ids
And
in QUERY try this WHERE coupon_id IN ("#coupon_ids")

Related

How to sort the string on the basis of numbers?

I am working on the sql query in which I want to sort the string on the basis of numbers.
I have one column (Column Name is Name) table in which there are multiple fields. On using ORDER BY NAME, it prints in the following way:
hello_world
hello_world10
hello_world11
hello_world12
hello_world13
hello_world14
hello_world15
hello_world4
hello_world5
For the above query, I have used ORDER BY NAME; but it doesn't seem to print on the basis of numbers.
Problem Statement:
I am wondering what sql query I need to write or what changes I need to make in my sql query above so that it prints everything on the basis of numbers, the o/p should be this:
hello_world
hello_world4
hello_world5
hello_world10
hello_world11
hello_world12
hello_world13
hello_world14
hello_world15
you want a numeric ordering, then you need to create a numeric value to order on.
currently you have strings.
if the pattern is true, then you can use a combination of string manipulation to trim off the first characters, which should leave only numbers, then use TO_NUMBER() to convert for the ordering
something like
select name
from mytable
order by to_number( replace( name, 'hello_world','' ))
I think the simplest solution for this particular case (where all the values have the same prefix) is:
order by length(name), name
Try this:
SELECT name,
CASE WHEN REGEXP_INSTR(name, '[0-9]') = 0 THEN 0
ELSE CAST(SUBSTR(name, REGEXP_INSTR(name, '[0-9]')) AS INT)
END AS progressive
FROM my_table
ORDER BY progressive;
we can order it using replace and cast methods.
I tried the following query
select Name, cast(REPLACE(Name, 'hello_world', '') as UNSIGNED ) as repl from Users order by repl;
To generage sample data
CREATE TABLE Users (
Name varchar(255) NOT NULL
);
insert into Users(Name) values
('hello_world'),
('hello_world4'),
('hello_world5'),
('hello_world10'),
('hello_world11'),
('hello_world12'),
('hello_world13'),
('hello_world14'),
('hello_world15')
;
EDIT
query without replaced column,
select City from Persons order by cast(REPLACE(City, 'hello_world', '') as UNSIGNED );
Though the question is about mysql.
I tried in sql server.
create table #t1 (id varchar(100));
insert into #t1 (id) values ('Pq1'),('pq3'),('pq2')
select * from #t
order by
CAST(SUBSTRING(id + '0', PATINDEX('%[0-9]%', id + '0'), LEN(id + '0')) AS INT)

Mysql remove special characters from a set

I want to remove a spacial character in my query can anyone help. This is my query
select sum(value) from table_1 where id in (1, 2,);
This 1,2, is fetch from other table using sub-query.
To remove the trailing colon, you can use trim():
SELECT TRIM(TRAILING ',' FROM '1,2,');
My guess is that you want to look for individual values in the list, especially because ids don't usually contain commas.
For that, you can do:
select sum(value)
from table_1
where find_in_set(id, '1, 2,') > 0;
If the values are coming from a subquery, you would be better off using the subquery directly (in most cases). The query would be something like:
select sum(value)
from table_1
where id in (<subquery>);
You would need to modify the subquery to return a list of ids, rather than all concatenated into one field.

MySQL GROUP_CONCAT multiple fields

I'm probably having a no-brain moment.
I want to return a series of numbers using GROUP_CONCAT from two fields in my database. I have done this so far using the following:
SELECT t_id,
CONCAT(GROUP_CONCAT(DISTINCT s_id),',',IFNULL(GROUP_CONCAT(DISTINCT i_id),'')) AS all_ids
FROM mytable GROUP BY t_id
This works fine but if i_id is NULL then of course I get an unnecessary comma. Is there a better way to do this so I don't end up with a comma at the end if i_id is NULL?
You need to use CONCAT_WS to avoid extra comma for NULL values, try this:
SELECT t_id,
CONCAT_WS(',', GROUP_CONCAT(DISTINCT s_id),
GROUP_CONCAT(DISTINCT i_id)) AS all_ids
FROM mytable
GROUP BY t_id;

SQL: Eliminate chains of duplicate in a GROUP_CONCAT

I'm running a query to analyse variations in Group_member_ID for some users.
What I would like to identify is the key variations in group_member_ids (eg Group1 on 01/08/2011, Group5 on 05/08/2011).
I came up with this command:
select id,
CAST(group_concat(concat('[',group_member_id,'-',from_unixtime(obs_time),']') order by obs_time) as CHAR(10000) CHARACTER SET utf8)
from Table1
where id=1
RESULT:
imei group/date
1[178-2011-06-13 18:58:31],[0-2011-06-13 19:20:56],[0-2011-06-17 17:21:57],[0-2011-06-19 16:53:29],[0-2011-06-22 16:41:11],[178-2011-09-30 16:43:11],[179-2011-10-01 18:43:11]
How can I eliminate the Group/date [0-2011-06-17 17:21:57],[0-2011-06-19 16:53:29],[0-2011-06-22 16:41:11] from this query as I already identified the first record for group_member_id=0 and the others do not matter for me...
In other words, I would like my final result to look like:
imei group/date
1[178-2011-06-13 18:58:31],[0-2011-06-13 19:20:56],[178-2011-09-30 16:43:11],[179-2011-10-01 18:43:11]
I'm stuck. I was thinking of using LIMIT in my group_concat but apparently it's not possible. Or is it?
Thanks for your answers.
TRY with GROUP BY
SELECT id, CAST( GROUP_CONCAT (
CONCAT('[',group_member_id,'-',from_unixtime(obs_time),']')
ORDER BY obs_time ) as CHAR(10000) CHARACTER SET utf8)
AS group_set
FROM table1
WHERE id=1
GROUP BY group_member_id

Select query with IN clause: filling the blanks

I have the following problem with a MySQL query in C#:
Given a list of strings, I want to query the database for any rows that match said strings. The strings are unique in that each string matches no more than one row. Today, my query looks something like this:
SELECT Id FROM SomeTable
WHERE SomeColumn IN("foo", "bar", "baz")
Now, ideally I would like to be able to map the result from the query directly to the list of strings I supplied in the IN clause:
String Returned ID
------------------------------------------
foo 123
bar NULL <-- Missing row filled with NULL
baz 42
This works fine as long as all strings I pass to the query match a row. When one is missing, however, I would like to fill in the blank with a NULL as in the example above.
Is there any way to accomplish this?
Edit: I should probably have pointed out that the solution must scale to a lot of strings. The way I do it right now is that I pass 100 at a time through the IN clause.
You could do this:
SELECT
helper.SomeColumn,
SomeTable.Id
FROM
(
SELECT 'foo' AS SomeColumn
UNION SELECT 'bar'
UNION SELECT 'baz'
) AS helper
LEFT JOIN SomeTable ON SomeTable.SomeColumn = helper.SomeColumn
Of course you can create the helper table (as a temp table) beforehand instead of inline.
Anyway, maybe it is smarter and more efficient to just do the query you have (WHERE SomeColumn IN (...)) and simply figure out the missing rows in your application. You will loop over them anyway, so you will notice.
What you could do is SELECT the set of strings as a result set and then LEFT JOIN on SomeTable.SomeColumn.
Try this:
SELECT Id
FROM (
SELECT "foo" SomeColumn
UNION ALL
SELECT "bar" AS SomeColumn
UNION ALL
SELECT "baz" AS SomeColumn
) b
LEFT JOIN
SomeTable a
ON a.SomeColumn = b.SomeColumn