I have two tables
Table1 with list of users comma separated
Name UserID
abc A,B,C,D
def A,B,C
Table2
Name UserID
abc A
abc B
abc C
def A
def B
I need to find the users that are in table1 for each Name but not in table2 (There won't ever be an instance when a UserID to Name pair is present in table2 but not in table1 as CSV).
The output should be
Name UserID
abc D
def C
I can do this with PHP but is there a way this can be done through a query? I am not sure where to begin in case I'm doing this as a query. Can I parse in MySQL using comma as delimiter?
I plugged your test data into a test schema in SQLFiddle and ran the query that follows.
Here's the link to SQLFiddle with the test and positive results:
http://sqlfiddle.com/#!2/83dfd/4/0
Here's the query:
SELECT
COALESCE(NORMALIZED_TABLE1.NAME, TABLE2.NAME) AS NAME,
COALESCE(NORMALIZED_TABLE1.USERID, TABLE2.USERID) AS USERID
FROM (
SELECT NAME,
SUBSTRING(
USERID
FROM CASE
WHEN INDEX_TABLE.POS = 1 THEN 1
ELSE INDEX_TABLE.POS + 1
END
FOR CASE LOCATE(',', USERID, INDEX_TABLE.POS + 1)
WHEN 0 THEN CHARACTER_LENGTH(USERID) + 1
ELSE LOCATE(',', USERID, INDEX_TABLE.POS + 1)
END
- CASE
WHEN INDEX_TABLE.POS = 1 THEN 1
ELSE INDEX_TABLE.POS + 1
END
) AS USERID
FROM TABLE1
INNER JOIN (
SELECT #rownum:=#rownum+1 POS
FROM (
SELECT 0 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 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, (
SELECT 0 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
) c, (SELECT #rownum:=0) r
) INDEX_TABLE
ON INDEX_TABLE.POS <= CHAR_LENGTH(TABLE1.USERID)
AND (
INDEX_TABLE.POS = 1
OR SUBSTRING(USERID FROM INDEX_TABLE.POS FOR 1) = ','
)
) AS NORMALIZED_TABLE1
LEFT OUTER JOIN TABLE2
ON NORMALIZED_TABLE1.NAME = TABLE2.NAME
AND NORMALIZED_TABLE1.USERID = TABLE2.USERID
WHERE TABLE2.NAME IS NULL;
If you have very long column width in table1 you might need to expand the "INDEX_TABLE" subquery. You can copy and paste over it with the code at this link to do so:
http://www.experts-exchange.com/Database/MySQL/A_3573-A-MySQL-Tidbit-Quick-Numbers-Table-Generation.html
If you table is fixed (you are wanted to work on those tables) then design a class to read data from them instead of directly saving the set data from those predefined tables; let your object to process the read data live across your application domain to get a full-blown accessibility. :-D
Related
My next database table will be set up more optimally. Unfortunately this one was already set up where one column [data] contains checkbox array values that were saved the following way:
value 1|~|value 1 value 2|~|value 2 value 3|~|value 3
Not optimal, I know.
What I need is a mysql query that select only the values in [data] column in front of the |~|. Basically think I need to select the only odd values.
Any help pointing me in the right direction is greatly appreciated. I tried an if statement in a query and it did not work. Of course I deleted that by mistake.
What I need is a mysql query that select only the
values in [data] column in front of the |~|.
One thing to note the numbers before |~| must be unique.
It will not show the same number twice.
Query
SELECT
DISTINCT
SUBSTRING (
record_data.column
, LOCATE('|~|', record_data.`column` , number_generator.number) - 1
, 1
) AS number
FROM (
SELECT
#row := #row + 1 AS number
FROM (
SELECT 0 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
) record_1
CROSS JOIN (
SELECT 0 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
) record_2
CROSS JOIN (
SELECT 0 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
) record_4
CROSS JOIN (
SELECT 0 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
) record_5
CROSS JOIN (
SELECT #row := 0
) AS init_user_params
) AS number_generator
CROSS JOIN (
SELECT
*
FROM (
SELECT 'value 1|~|value 1 value 2|~|value 2 value 3|~|value 3' AS `column`
) AS record
) AS record_data
WHERE
LOCATE('|~|', record_data.`column` , number_generator.number) <> 0
Result
| number |
| ------ |
| 1 |
| 2 |
| 3 |
demo
I have a table in mysql which looks like below.
id cust_id date data
1 1 1/1/2018 a b c d e f g
2 1 2/1/2018 h I j k l m n
Here in this example data column is having huge data seperated by space like a b c d, I would like to show case as in row like below
id cust_id date data
1 1 1/1/2018 a
1 1 1/1/2018 b
1 1 1/1/2018 c
1 1 1/1/2018 d
2 2 2/1/2018 h
2 2 2/1/2018 i
2 2 2/1/2018 j
2 2 2/1/2018 k
I have checked few option like using unpivot function, but unable to achieve my output.
Thanks in advance !!
select
tablename.id,
tablename.date
,SUBSTRING_INDEX(SUBSTRING_INDEX(tablename.data, ' ', numbers.n), ' ', -1) name
from
(
SELECT #row := #row + 1 as n 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) t,
(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) t1,
(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) t2,
(SELECT #row:=0) r
) numbers INNER JOIN Table1 tablename
on CHAR_LENGTH(tablename.data)
-CHAR_LENGTH(REPLACE(tablename.data, ' ', ''))>=numbers.n-1
order by
id, n
Check link for output
http://sqlfiddle.com/#!9/fa0dcb/1
EXPLANATION:
First go through the inner query i.e.
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
This will generate a table of 10 rows with 10 numbers.
Now the other query :
SELECT #row := #row + 1 as n 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) t,
(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) t1
Since above query is generating row numbers from below table 't' and table 't1' which is separated by ',' means that they are producing Cartesian product of their total rows.
For example: t have 10 rows and t1 also have 10 rows so, there Cartesian product produces 100 rows. So #row variable incremented 100 times and gives 100 rows of 100 numbers from 1 to 100.
The below query:
SUBSTRING_INDEX(SUBSTRING_INDEX(tablename.data, ' ', numbers.n), ' ', -1)
this one will take "a b c d e f g h" one by one.
For example:
take numbers.n = 1
then inner substring_index will find index of first space and will return string before that index i.e. 'a'
and then outer substring_index will find the space from the end of the resulting string and will give the last character from the string i.e. 'a'.
Now if you
take numbers.n = 2
then inner substring_index will find index of first space and will return string before that index i.e. 'a b'
and then outer substring_index will find the space from the end of the resulting string and will give the last character from the string i.e. 'b'
Always try to breakdown the query like this and you will able to understand the query in simpler way.
I want to a MySQL query to select the records separately from following table
ID AgentID Name Return Date
1 1,2,3 A 2016-05-22,2016-02-1,2016-1-15
2 2,4 B 2016-03-22,2016-04-1
Expecting Answer
ID AgentID Name Return Date
1 1 A 2016-05-22
1 2 A 2016-02-1
1 3 A 2016-1-15
2 2 B 2016-03-22
2 4 B 2016-04-1
You can use MySQL SUBSTRING_INDEX(). It will return the sub-string from the given comma separated string before a specified number of occurrences of the delimiter.
Try this, It seems to work fine:
SELECT ID
,SUBSTRING_INDEX(SUBSTRING_INDEX(t.AgentID, ',', n.n), ',', -1) Agent
,Name
,SUBSTRING_INDEX(SUBSTRING_INDEX(t.Return_Date, ',', n.n), ',', -1) Return_Date
FROM table1 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.Return_Date) - LENGTH(REPLACE(t.Return_Date, ',', '')))
ORDER BY ID;
Check this..
SQL Fiddle HERE
For further Study go on MySQL Split String Function
if your values in tblA and you want to insert into tblB than query like this
insert into tblB (date) select date from tblA;
INSERT INTO second_table (
Field_1,
Field_2,
Field_3)
SELECT Field_1,
Field_2,
Field_3
FROM first_table;
I want to a MySQL query to select the records separately from following table
ID AgentID Name Return Date
1 1,2,3 A 2016-05-22,2016-02-1,2016-1-15
2 2,4 B 2016-03-22,2016-04-1
Expecting Answer
ID AgentID Name Return Date
1 1 A 2016-05-22
1 2 A 2016-02-1
1 3 A 2016-1-15
2 2 B 2016-03-22
2 4 B 2016-04-1
You can use MySQL SUBSTRING_INDEX(). It will return the sub-string from the given comma separated string before a specified number of occurrences of the delimiter.
Try this, It seems to work fine:
SELECT ID
,SUBSTRING_INDEX(SUBSTRING_INDEX(t.AgentID, ',', n.n), ',', -1) Agent
,Name
,SUBSTRING_INDEX(SUBSTRING_INDEX(t.Return_Date, ',', n.n), ',', -1) Return_Date
FROM table1 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.Return_Date) - LENGTH(REPLACE(t.Return_Date, ',', '')))
ORDER BY ID;
Check this..
SQL Fiddle HERE
For further Study go on MySQL Split String Function
if your values in tblA and you want to insert into tblB than query like this
insert into tblB (date) select date from tblA;
INSERT INTO second_table (
Field_1,
Field_2,
Field_3)
SELECT Field_1,
Field_2,
Field_3
FROM first_table;
I have following below 2 tables.Here is schema Sqlfiddle for it.
Table 1
Transaction Items
----------- -------------
T1 I1,I3,I7
T2 I7,I2,I3
T3 I1,I2,I3
T4 I2,I3
T5 I2,I3,I4,I5
Table 2
Id Items
------ --------
1 I1,I3
2 I1,I2
3 I2,I4
4 I2,I3
5 I4,I5
I want result in Table 3 like for each record in Table2 like 1st row I1,I3how many time it occurs in Table 1 in each record.It should display in SOT column as answer.Here for 1st one is 2.
Table 3
Id Items SOT
------ ------ --------
1 I1,I3 2
2 I1,I2 1
3 I2,I4 1
4 I2,I3 4
5 I4,I5 1
Can you please advise me for this? I have think of find_in_set but It works for only 1 string to match.
As a demonstration, the following SQL will get you the results you want (I think) with up to 100 comma separated values in Table2.Items.
As you can see it is not pleasant to read, and anyone who comes to maintain this statement in the future would probably be very confused. I would not recommend doing something like this in live code.
SELECT Id, COUNT(*)
FROM
(
SELECT Transaction, anItemCount, ItemVal.Id, COUNT(anItem) AS aCount
FROM
(
SELECT DISTINCT Id, SUBSTRING_INDEX(SUBSTRING_INDEX(Items, ',', AnInt), ',', -1) AS anItem
FROM Table2,
(
SELECT 1 + Units.i + Tens.i * 10 as AnInt
FROM
(SELECT 0 AS 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,
(SELECT 0 AS 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
) Ints
) ItemVal
INNER JOIN
(
SELECT Id, COUNT(DISTINCT SUBSTRING_INDEX(SUBSTRING_INDEX(Items, ',', AnInt), ',', -1)) AS anItemCount
FROM Table2,
(
SELECT 1 + Units.i + Tens.i * 10 as AnInt
FROM
(SELECT 0 AS 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,
(SELECT 0 AS 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
) Ints
GROUP BY Id
) ItemCnt
ON ItemVal.Id = ItemCnt.Id
INNER JOIN Table1
ON FIND_IN_SET(ItemVal.anItem, Table1.Items)
GROUP BY Transaction, anItemCount, ItemVal.Id
HAVING anItemCount = aCount
) Sub1
GROUP BY Id
If Table2.Items only ever contains 2 values then this could be cut down to:-
SELECT Id, COUNT(*)
FROM
(
SELECT Table1.Transaction, ItemVal.Id, COUNT(anItem) AS aCount
FROM
(
SELECT Id, SUBSTRING_INDEX(Items, ',', 1) AS anItem
FROM Table2
UNION
SELECT Id, SUBSTRING_INDEX(Items, ',', -1) AS anItem
FROM Table2
) ItemVal
INNER JOIN Table1
ON FIND_IN_SET(ItemVal.anItem, Table1.Items)
GROUP BY Table1.Transaction, ItemVal.Id
HAVING aCount = 2
) Sub1
GROUP BY Id;
It could also be done simply when there are only 2 values in Table2.Items with the following:-
SELECT Table2.Id, COUNT(Table1.Transaction) AS aCount
FROM Table2
INNER JOIN Table1
ON FIND_IN_SET(SUBSTRING_INDEX(Table2.Items, ',', 1), Table1.Items)
AND FIND_IN_SET(SUBSTRING_INDEX(Table2.Items, ',', -1), Table1.Items)
GROUP BY Table2.Id
But still hardly pleasant.
SQL Fiddle here:-
http://www.sqlfiddle.com/#!2/03fe9/19