SQL query with subquery - mysql

My data is like this:
data1_qqq_no_abc_ccc
data1_qqq_abc_ccc
data2_qqq_no_abc_ccc
data2_qqq_abc_ccc
data3_qqq_no_abc_ccc
data4_qqq_no_abc_ccc
data4_qqq_abc_ccc
...
Now I want to get the fields where data has substring _no_abc_ccc, but doesn't have _abc_ccc. In the above example, its data3
I am trying to create a query for it.
rough one is
select SUBSTRING_INDEX(name, 'abc', 1)
from table1
where SUBSTRING_INDEX(name, 'abc', 1) not LIKE "%no"
and NOT IN (select SUBSTRING_INDEX(name, '_no_abc', 1)
from table
where name LIKE "%no_abc");

Something like this (?)
create table t (
col text
);
insert into t
values
('data1_qqq_no_abc_ccc'),
('data1_qqq_abc_ccc'),
('data2_qqq_no_abc_ccc'),
('data2_qqq_abc_ccc'),
('data3_qqq_no_abc_ccc'),
('data4_qqq_no_abc_ccc'),
('data4_qqq_abc_ccc');
select f from (
select SUBSTRING_INDEX(col, '_', 1) as f, SUBSTRING_INDEX(col, '_', -3) as s from t
) tt
group by f
having
count(case when s = 'no_abc_ccc' then 1 end) > 0
and
count(case when s like '%qqq_abc%' then 1 end) = 0
demo

Related

mysql query with grouping and concatenate rows into one row

I have the table in mysql with records:
I've written the sql query:
SELECT COUNT(*) AS number_of_contacts, channel_id, direction
FROM cic_case_contacts
WHERE case_id = 328678
GROUP BY channel_id, direction
and the result looks like:
I would like to obtain something like below(based on above data):
I was trying to obtaining that with sql query by using my_sql_function GROUP_CONCAT but it dosen't work:
SELECT COUNT(*) AS number_of_contacts, channel_id, GROUP_CONCAT(direction SEPARATOR ', ') AS directions
FROM cic_case_contacts
WHERE case_id = 328678 AND id IN(149196, 149195, 149194, 149193, 149192) AND `office_id` = 10
GROUP BY channel_id
ORDER BY channel_id
I would be greateful for help.
You can use GROUP_CONCAT on a sub query as follows:
SELECT channelid, GROUP_CONCAT(
CONCAT(direction, ': ', c)
ORDER BY direction
SEPARATOR ', '
) AS summary
FROM (
SELECT channelid, direction, COUNT(*) AS c
FROM t
GROUP BY channelid, direction
) x
GROUP BY channelid
Or simply use conditional aggregation:
SELECT channelid, CONCAT_WS(', ',
CONCAT('in: ', COUNT(CASE WHEN direction = 'in' THEN 1 END)),
CONCAT('out: ', COUNT(CASE WHEN direction = 'out' THEN 1 END))
) AS summary
FROM t
GROUP BY channelid
You can use Concat in MySQL
drop table if exists Demo;
CREATE TABLE Demo
(
ID INT AUTO_INCREMENT PRIMARY KEY,
channelid int,
Name VARCHAR(20)
);
INSERT INTO Demo(channelid, Name)VALUES
(1,'in'),(1,'out'),(1,'in'),(1,'out'),(2,'in'),(2,'out'),(1,'in'),(1,'out'),(1,'in'),(2,'out'),(2,'in'),(2,'out'),(2,'in'),(1,'in'),(1,'in');
Query
SELECT SQL_CALC_FOUND_ROWS
channelid,
group_concat ( concat(name,':',channelid) )
FROM Demo
group by channelid;
SELECT FOUND_ROWS();
See the results the the fiddle
Please find below working code as per your requirement :
select tb.channelid, group_concat
(
concat(tb.name,':',tb.MyCol2Count)
) as v1
from
(Select tbl.channelid,tbl.name,(LENGTH(tbl.val) - LENGTH(REPLACE(tbl.val,",","")) + 1) AS MyCol2Count
from
(SELECT channelid, group_concat
(
concat(name,':',channelid)
) as val,name
FROM Demo
group by channelid,Name) as tbl) as tb group by tb.channelid
You can check on below screenshot : http://springinfosoft.com/code/Groupby_code.png

How to split the string in a single column and arrange the same in the same column in SQL

I have a column as below
Products
jeans,oil
jeans,shampoo
I want to split the strings and use it in the same column using SQL. The result I want is
Products count
jeans 2
oil 1
shampoo 1
Could you please guide me in getting this result
Thank you
You are storing CSV data in your SQL table, which is not a good thing. But it looks like you are trying to move away from that, which is a good thing. Here is one option using a union with SUBSTRING_INDEX:
SELECT Products, COUNT(*) AS count
FROM
(
SELECT SUBSTRING_INDEX(Products, ',', 1) AS Products FROM yourTable
UNION ALL
SELECT SUBSTRING_INDEX(Products, ',', -1) FROM yourTable
) t
GROUP BY Products
ORDER BY
count DESC, Products;
Demo
Firstly you need to split the data into two columns like
SELECT CASE
WHEN name LIKE '%,%' THEN LEFT(name, Charindex(' ', products) - 1)
ELSE name
END,
CASE
WHEN name LIKE '%,%' THEN RIGHT(name, Charindex(' ', Reverse(products)) - 1)
END
FROM YourTable
then you need to union this with the same table... and the final code will look like...
select count( distinct abc), abc from
(
SELECT CASE
WHEN PA_NAME LIKE '% %' THEN LEFT(PA_NAME, Charindex(' ', PA_NAME) - 1)
ELSE PA_NAME
END [abc]
FROM phparty
union all
SELECT CASE
WHEN PA_NAME LIKE '% %' THEN RIGHT(PA_NAME, Charindex(' ', Reverse(PA_NAME)) -1)
END [abc]
FROM phparty
) t group by abc
here you can replace pa_name with your_column_name

How to select a primary key which has exact foreign keys matches a given list of values?

For example:
pk_ref fk
====== ===
1 a
1 b
1 c
2 a
2 b
2 d
How do I do a query like the "pseudo" query:
select distinc pk_ref
where fk in all('a', 'c');
The return query result must match all given values for the foreign key in the list.
The result should be:
1
While the following select must not return any records.
select distinc pk_ref
where fk in all('a', 'c', 'd');
How do I do that?
Try this
select pk_ref
from yourtable
group by pk_ref
having count(case when fk = 'a', then 1 end) >= 1
and count(case when fk = 'c' then 1 end) >= 1
To do it dynamically. (considering you are using SQL SERVER)
Create a split string function and pass the input as comma separated values
Declare #input varchar(8000)= 'a,c',#cnt int
set #cnt = len(#input)-len(replace(#input,',','')) + 1
select pk_ref
from yourtable
Where fk in (select split_values from udf_splitstring(#input , ','))
group by pk_ref
having count(Distinct fk) >= #cnt
You can create a split string function from the below link
https://sqlperformance.com/2012/07/t-sql-queries/split-strings
:list is the input list (bind variable). The difference of length() return values is the number of commas in the bind variable. This query, or something very close to it, should work in pretty much any DB product. Tested in Oracle.
select pk_ref
from tbl -- enter your table name here
where ',' || :list || ',' like '%,' || fk || ',%'
group by pk_ref
having count(distinct fk) = 1 + length(:list) - length(replace(:list, ',', ''))
If you can pass the IN operator values as Set, then you can do this as below
Schema:
SELECT * INTO #TAB FROM (
SELECT 1 ID, 'a' FK
UNION ALL
SELECT 1, 'b'
UNION ALL
SELECT 1, 'c'
UNION ALL
SELECT 2, 'a'
UNION ALL
SELECT 2, 'b'
UNION ALL
SELECT 2, 'd'
UNION ALL
SELECT 1, 'a'
)AS A
Used CTE to make 'a','c' as Set
;WITH CTE AS (
SELECT 'a' FK --Here 'a','c' passed as a Set through CTE
UNION
SELECT 'c'
)
,FINAL AS(
SELECT DENSE_RANK() OVER (PARTITION BY ID ORDER BY (FK))AS COUNT_ID, ID, FK
FROM #TAB where FK IN (select FK FROM CTE)
)
SELECT ID FROM FINAL WHERE COUNT_ID>=(SELECT COUNT( FK) FROM CTE)
Select pk_ref where fk='a' and pk_ref in (select pk_ref where fk='c' from yourtable) from yourtable;
or
select pk_ref where fk='a' from yourtable intersect select pk_ref where fk='c' from yourtable;
DECLARE #inputVariable VARCHAR(200) = 'a,b,c,d'
DECLARE #inputValue INT
DECLARE #tblInput TABLE
(
FK VARCHAR(100)
)
INSERT INTO #tblInput
SELECT SUBSTRING( #inputVariable+',',RN,1)
FROM (SELECT TOP 100 ROW_NUMBER() OVER(ORDER BY s.object_id) RN
FROM sys.objects s) s
where LEN(#inputVariable) >= RN
AND SUBSTRING(','+ #inputVariable,RN,1) = ','
SELECT #inputValue = COUNT(1) FROm #tblInput
--#inputVariable
DECLARE #tbl TABLE
(
ID INT,
FK VARCHAR(100)
)
INSERT INTO #tbl
SELECT 1 ID, 'a' FK
UNION ALL
SELECT 1, 'b'
UNION ALL
SELECT 1, 'c'
UNION ALL
SELECT 2, 'a'
UNION ALL
SELECT 2, 'b'
UNION ALL
SELECT 2, 'd'
UNION ALL
SELECT 1, 'a'
SELECT t.ID ,COUNT(DISTINCT t.FK)
FROM #tbl t
INNER JOIn #tblInput ti
ON t.FK = ti.FK
GROUP BY ID
HAVING COUNT(DISTINCT t.FK) = #inputValue

Get Values not in the second table using find_in_set

I have two tables and i need to get list of all store_ids that are not in the other table
BusinessUnit Table User Table
StoreId(varchar) StoreId(varchar)
1 1,2
2 3,4
3 1,5
4 4,6
7 4
How to get values of storeid 5,6 which are not present in the business unit table but are present in the user Table? Tried to use several using find_in_set and nothing works.
Use SUBSTRING_INDEX to get all the values from the CSV field. Since there can be up to 6 IDs in the CSV, you need to call it once for each position.
SELECT u.StoreId
FROM (
select substring_index(StoreId, ',', 1) AS StoreID
FROM User
UNION
select substring_index(substring_index(StoreId, ',', 2), ',', -1)
FROM User
UNION
select substring_index(substring_index(StoreId, ',', 3), ',', -1)
FROM User
UNION
select substring_index(substring_index(StoreId, ',', 4), ',', -1)
FROM User
UNION
select substring_index(substring_index(StoreId, ',', 5), ',', -1)
FROM User
UNION
select substring_index(substring_index(StoreId, ',', 6), ',', -1)
FROM User) AS u
LEFT JOIN BusinessUnit AS b ON u.StoreId = b.StoreID
WHERE b.StoreId IS NULL
DEMO
IF you know all the possible values (and the number of them is reasonably manageable) you can populate a new table with them (you can make it TEMPORARY or just DROP it afterwards), and do this
SELECT *
FROM (
SELECT allIDs.Id
FROM allIDs
INNER JOIN `User` AS u
-- ON CONCAT(',', u.StoreID, ',') LIKE CONCAT('%,', allIDs.Id, ',%')
ON FIND_IN_SET(allIDs.Id, u.StoreID)
) AS IDsInUserTable
LEFT JOIN `BusinessUnit` AS b ON IDsInUserTable.Id = b.StoreID
HAVING b.StoreID IS NULL
;
In this example, allIDs is the aforementioned "possible values" table.

mysql select substrings and group them by column

I am trying to divide data in one onf the tables on my MySQL database.
Column contains data like this:
de:"Sweatjacke*";en:"jacket*";pl:"bluza*";
de:"*";en:"*";pl:"bluza*";
fr:"*";de:"*";en:"*";pl:"dres junior*";cz:"*";
pl:"bluza";
And I am trying to divide all of the translations into separate columns. Already came with solution to do this by using:
SELECT
SUBSTRING_INDEX(SUBSTRING_INDEX(name, ';', 1), ';', -1) as tr1,
SUBSTRING_INDEX(SUBSTRING_INDEX(name, ';', 2), ';', -1) as tr2,
SUBSTRING_INDEX(SUBSTRING_INDEX(name, ';', 3), ';', -1) as tr3,
SUBSTRING_INDEX(SUBSTRING_INDEX(name, ';', 4), ';', -1) as tr4,
SUBSTRING_INDEX(SUBSTRING_INDEX(name, ';', 5), ';', -1) as tr5
FROM product;
statement, but that results in:
tr1 tr2 tr3 tr4 tr5
fr:"*" de:"*" en:"*" pl:"bluza*" cz:"*"
fr:"*" de:"Sweatjacke*" en:"jacket*" pl:"bluza*" cz:"*"
de:"Sweatjacke*" en:"jacket*" pl:"bluza*"
And I want to have the results gruped by translation type (pl/de/en) so in each collumn one type of translatoin is present. For example in column1 = pl:, column2 = en: etc.
Any one came across similar problem and knows a way to solve it?
You need to unpivot the data, then select the first and second part of each value and then re-aggregate it.
However, a better form for the data is really to have language/translation. The following produces this:
select substring_index(tr, ':', 1) as l, substring_index(tr, ':', 2) as t, name
from (select SUBSTRING_INDEX(SUBSTRING_INDEX(name, ';', n.n), ';', -1) as tr, n, name
from product p cross join
(select 1 as n union all select 2 union all select 3 union all select 4 union all
select 5
) n
) n
You would probably want an "id" column or "word" column to identify each row, rather than the name column.
You can now pivot this result to get what you want:
select max(case when l = 'en' then name end) as en,
max(case when l = 'fr' then name end) as fr,
max(case when l = 'de' then name end) as de,
max(case when l = 'pl' then name end) as pl,
max(case when l = 'cz' then name end) as cz
from (select substring_index(tr, ':', 1) as l, substring_index(tr, ':', 2) as t, name
from (select SUBSTRING_INDEX(SUBSTRING_INDEX(name, ';', n.n), ';', -1) as tr, n, name
from product p cross join
(select 1 as n union all select 2 union all select 3 union all select 4 union all
select 5
) n
) n
) lt
group by name;
Managed to solve it by using some of the string related functions funcitons:
SELECT
SUBSTRING_INDEX( SUBSTRING( name, LOCATE( "pl:", name ) , 150 ) , ';', 1 ) AS pl,
SUBSTRING_INDEX( SUBSTRING( name, LOCATE( "en:", name ) , 150 ) , ';', 1 ) AS en,
SUBSTRING_INDEX( SUBSTRING( name, LOCATE( "de:", name ) , 150 ) , ';', 1 ) AS de,
SUBSTRING_INDEX( SUBSTRING( name, LOCATE( "fr:", name ) , 150 ) , ';', 1 ) AS fr
FROM product
Thanks to everyone for help.
As far as I understand you want to UNPIVOT your data. There is no such function in MySQL, so you might want to export your data into MSSQL (you can use free MSSQL Express) and use UNPIVOT function: http://technet.microsoft.com/en-us/library/ms177410(v=sql.105).aspx