Mysql problem to see if two selects are the same - mysql

SELECT table_grouping_code, gui_field_code, gui_interface_id, dictionary_code, property_name, position INTO #test
FROM table_grouping_layout
WHERE company_code = "TEST";
SELECT table_grouping_code, gui_field_code, gui_interface_id, dictionary_code, property_name, position INTO #doximtrx
FROM table_grouping_layout
WHERE company_code = "DOXIMTRX";
select #test = #doximtrx;
I tried this, that seems very logica to me, but mysql says: ERROR CODE 1222: the used select statement have a different number of columns. How can it be possible?? I copied the query, only changing the code.
Example of data in the table

You are trying to select many columns into a single variable. The correct syntax for that part of your query is:
SELECT
GROUP_CONCAT(table_grouping_code ORDER BY table_grouping_code)
, GROUP_CONCAT(gui_field_code ORDER BY gui_field_code)
, GROUP_CONCAT(gui_interface_id ORDER BY gui_interface_id)
, GROUP_CONCAT(dictionary_code ORDER BY dictionary_code)
, GROUP_CONCAT(property_name ORDER BY property_name)
, GROUP_CONCAT(position ORDER BY position)
FROM
table_grouping_layout
WHERE
company_code = 'TEST'
INTO
#t1, #t2, #t3, #t4, #t5, #t6;
SELECT
GROUP_CONCAT(table_grouping_code ORDER BY table_grouping_code)
, GROUP_CONCAT(gui_field_code ORDER BY gui_field_code)
, GROUP_CONCAT(gui_interface_id ORDER BY gui_interface_id)
, GROUP_CONCAT(dictionary_code ORDER BY dictionary_code)
, GROUP_CONCAT(property_name ORDER BY property_name)
, GROUP_CONCAT(position ORDER BY position)
FROM
table_grouping_layout
WHERE
company_code = 'DOXIMTRX'
INTO
#d1, #d2, #d3, #d4, #d5, #d6;
How to compare results is a different story:
SELECT ifNull(
#t1 = #d1
and #t2 = #d2
and #t3 = #d3
and #t4 = #d4
and #t5 = #d5
and #t6 = #d6
, false
) as result;
TEST DATA:
select * from table_grouping_layout;
table_grouping_code
gui_field_code
gui_interface_id
dictionary_code
property_name
position
company_code
1
2
3
4
5
6
DOXIMTRX
1
3
3
4
5
6
TEST
1
1
3
4
5
6
DOXIMTRX
1
2
3
4
5
6
TEST
QUERY RESULT:
result
0

Variables are meant to hold one value. Neither one row nor one column nor one table.
Comparing two data sets can be achieved with a combination of UNIONand EXCEPT or with a full outer join. Unfortunately, MySQL does neither support EXCEPT nor FULL OUTER JOIN.
Here is a workaround:
with t as (select * from table_grouping_layout where company_code = 'TEST')
, d as (select * from table_grouping_layout where company_code = 'DOXIMTRX')
select 'MISMATCH' as status, t.position
from table_grouping_layout t
join table_grouping_layout d
on t.position = d.position
and not
(
t.table_grouping_code <=> t.table_grouping_code and
t.gui_field_code <=> t.gui_field_code and
t.gui_interface_id <=> t.gui_interface_id and
t.dictionary_code <=> t.dictionary_code and
t.property_name <=> t.property_name
)
union all
select 'TEST MISSING' as status, position
from d
where position not in (select position from t)
union all
select 'DOXIMTRX MISSING' as status, position
from t
where position not in (select position from d)
order by position;
Another approach using aggregation:
select
position,
case
when sum(company_code = 'TEST') = 0 then 'TEST MISSING'
when sum(company_code = 'DOXIMTRX') = 0 then 'DOXIMTRX MISSING'
when not
(
max(table_grouping_code) <=> min(table_grouping_code) and count(table_grouping_code) in (0,2)
max(gui_field_code) <=> min(gui_field_code) and count(gui_field_code) in (0,2)
max(gui_interface_id) <=> min(gui_interface_id) and count(gui_interface_id) in (0,2)
max(dictionary_code) <=> min(dictionary_code) and count(dictionary_code) in (0,2)
max(property_name) <=> min(property_name) and count(property_name) in (0,2)
) then 'MISMATCH'
else 'MATCH' end as status
from table_grouping_layout
where company_code in ('TEST', 'DOXIMTRX')
group by position
order by position;

Related

Sql query with three conditions

I have a database with a table having content as below :
message_number message_type message_chat
0 IN Hi
1 OB Hello
2 IN Help
3 IN Want to find this thing
4 OB Sure
5 OB Please let me know
I have written 5 rows since i want to incorporate all possible cases that i want in my query in the example table that i showed.
Now in my query output, i want something like :
message_in message_out
Hi Hello
Help NULL
Want to find this string Sure
NULL Please let me know
So the cases that i want to consider are :
suppose if message_number=0 and message_number=1 both have message_type value as IN then put message_chat_in as message_chat(at message_number=0) and message_chat out as NULL and the iterate over message_number=1
if message_number =0 have message_type=IN and message_number =1 have message_type=OB, then show message_chat(at message_number=0) as message_chat_in and message_chat(at message_number=1) as message_out and dont iterate over message_number=1;
hope i have clarified the condition though i have included all three condition in the expected output.How should my sqlquery look like?
Edit : I am using mysql version 5.5.8
Try the following query
SELECT
q1.message_number in_num,
q1.message_chat in_chat,
q2.message_number out_num,
q2.message_chat out_chat
FROM
(
SELECT *,#i1:=IFNULL(#i1,0)+1 num
FROM Chat
ORDER BY message_number
) q1
LEFT JOIN
(
SELECT *,#i2:=IFNULL(#i2,0)+1 num
FROM Chat
ORDER BY message_number
) q2
ON q2.num=q1.num+1 AND q2.message_type<>q1.message_type
WHERE q1.message_type='IN'
UNION ALL
SELECT
q1.message_number in_num,
q1.message_chat in_chat,
q2.message_number out_num,
q2.message_chat out_chat
FROM
(
SELECT *,#i3:=IFNULL(#i3,0)+1 num
FROM Chat
ORDER BY message_number
) q1
RIGHT JOIN
(
SELECT *,#i4:=IFNULL(#i4,0)+1 num
FROM Chat
ORDER BY message_number
) q2
ON q2.num=q1.num+1 AND q2.message_type<>q1.message_type
WHERE q2.message_type='OB'
AND q1.message_type IS NULL
ORDER BY IFNULL(in_num,out_num)
SQL Fiddle - http://sqlfiddle.com/#!9/95a515/1
The second variant
SET #i1 = 0;
SET #i2 = 0;
SET #i3 = 0;
SET #i4 = 0;
-- the same query
SQL Fiddle - http://sqlfiddle.com/#!9/95a515/2
Or
SELECT 0,0,0,0 INTO #i1,#i2,#i3,#i4;
-- the same query
SQL Fiddle - http://sqlfiddle.com/#!9/95a515/5
why not using a analytic function here? I would do it with Lead() like this:
with inc as (
--Do the incorporation in this block. could be subquery too
--but its easier to read this way.
select
case when message_type = 'IN'
then message_chat
end as message_in
,case when LEAD(message_type) OVER (Order by message_number) = 'OB' --get the next message by number if it is type OB
then LEAD(message_chat) OVER (order by message_number)
end as message_out
from input
)
select *
from inc
where coalesce(message_in, message_out) is not null --filter out rows where with in & out is null
Ok, since there is no analytical functions in MySQL less than 8 the code may not be easy to follow:
with data_rn as
(
-- this isolate consecutive rows with the same message_type
select d1.*, count(d2.message_number) rn
from data d1
left join data d2 on d1.message_number > d2.message_number and d1.message_type != d2.message_type
group by d1.message_number
),
data_rn2 as
(
-- this marks the rows where new rows has to be added (i.e. when rn2 != 0)
select d1.*, count(d2.message_number) rn2
from data_rn d1
left join data_rn d2 on d1.rn = d2.rn and d1.message_type = d2.message_type and d1.message_number > d2.message_number
group by d1.message_number
),
data_added as
(
-- this add new rows
select message_number, message_type, message_chat
from data_rn2
union all
select message_number - 0.5, 'OB', NULL from data_rn2 where message_type = 'IN' and rn2 != 0
union all
select message_number - 0.5, 'IN', NULL from data_rn2 where message_type = 'OB' and rn2 != 0
order by message_number
), data_added_rn as
(
-- this compute new row numbering
select d1.*, ceil((count(d2.message_number)+1)/2) rn
from data_added d1
left join data_added d2 on d1.message_number > d2.message_number
group by d1.message_number
)
-- this will do the final formating
select max(case when message_type = 'IN' then message_chat end) message_in,
max(case when message_type = 'OB' then message_chat end) message_out
from data_added_rn
group by rn
demo
I have tried to comment each section appropriately.

How to select all values of a field that has specific values in another field?

I have a table in which the field 'id_px' can have some repeated values because it has a different value in the field 'id_category' and I want to retrieve all values on 'id_px' that has the exact values that I pass. For example:
SELECT id_px FROM my_table WHERE id_category = 1 **AND** id_category = 32;
I found a way that retrieves me the result that I want:
SELECT id_px
FROM my_table
GROUP BY id_px
HAVING SUM(id_category NOT IN (1,32)) = 0
AND SUM(id_category = 1) = 1
AND SUM(id_category = 32) = 1
but I want to use it whitout the HAVING clause because I have to use some UNION clause.
Hope you can help me, thanks in advance.
I suggest some ways:
3- 3rd one: (Worked and marked as an Answer)
SELECT tbl.id_px FROM
(SELECT id_px ,
SUM(id_category NOT IN (1,32)) as b ,
SUM(id_category = 1) as t1 , SUM(id_category = 32) as t2
FROM my_table
GROUP BY id_px) as tbl
WHERE tbl.b = 0 AND tbl.t1 = 1 AND tbl.t2 = 1
4- Re-Building Query-2 :
4.1-first steps of rebuilding: (inefficient)
SELECT tbl.id_px FROM
(SELECT id_px , CONCAT('-,' , GROUP_CONCAT(id_category),',') as gr
FROM my_table
GROUP BY id_px
) as tbl
WHERE
INSTR( tbl.gr , ',1,' )>0
AND INSTR( tbl.gr , ',32,' )>0
AND LENGTH(tbl.gr)-LENGTH(REPLACE(REPLACE(tbl.gr,',1,' ,''), ',32,' ,'')) = LENGTH(CONCAT(',1,' , ',32,' ))
last condition in WHERE is replacing 1 and 32 from tbl.gr and comparing reduced LENGTH if reduced length is equal to 1 and 32 string, there were just 1 and 32 so rewrite query to this one:
4.2- New possibly working query: (simplified)
SELECT tbl.id_px FROM
(SELECT id_px , GROUP_CONCAT(id_category) as gr
FROM my_table
GROUP BY id_px
) as tbl
WHERE
tbl.gr = '1,32' or tbl.gr = '32,1'
Without any sample data it seems these are ok, but they didn't good answer while problem is limiting id_category to exactly have two values and no other id_category.
NOTE: These two queries, selects id_px that has id_category 1,32 and maybe many other id_category, so these are not acceptable answer for this question
2- Selecting id_px by join
SELECT a.id_px
FROM my_table as a
LEFT JOIN my_table as b
ON a.id_px = b.id_px
WHERE a.id_category = 1 AND b.id_category = 32
GROUP BY a.id_px
1- Using group by and searching in id_px:
SELECT tbl.id_px FROM
(SELECT id_px , CONCAT('-,' , GROUP_CONCAT(id_category),',') as gr
FROM my_table
GROUP BY id_px
) as tbl
WHERE
INSTR( tbl.gr , ',1,' )>0
AND INSTR( tbl.gr , ',32,' )>0

MYSQL CASE/IF over a value selected with SELECT

I'd like to run a CASE statement or IF on the COUNT_A returned by the select query below and set the value of a variable A_VAL.
SELECT A_DATE, COUNT(A_INS_NAM) AS COUNT_A
FROM TABLE1
WHERE A_INS_NAM IN
(
SELECT A_INS_NAM FROM IWD
WHERE I_ID IN
(
SELECT IM_ID FROM TIM WHERE IM_ID = (
SELECT T_ID FROM TWS WHERE TN = 'abced')
)
) AND A_DATE BETWEEN '2014-01-01' AND '2015-05-01' AND A_INS_NAM NOT LIKE '%pk%'
I'd like the output to have 2 columns namely A_DATE, A_VAL. The value of A_VAL gets set based on
If COUNT_A = 10, then A_VAL = 1
If COUNT_A = 20, then A_VAL = 2
If COUNT_A between 30 & 50, then A_VAL = 3
If COUNT_A > 50, then A_VAL = 5
Could I get someone's help please?
You should use joins instead of sub queries for better performance something like below, also you are using an aggregate function without providing grouping criteria so it will result as a single row for this i have added GROUP BY t.A_DATE in below query
SELECT
t.A_DATE,
CASE
WHEN COUNT(t.A_INS_NAM) = 10 THEN 1
WHEN COUNT(t.A_INS_NAM) = 20 THEN 2
WHEN COUNT(t.A_INS_NAM) BETWEEN 30 AND 50 THEN 3
WHEN COUNT(t.A_INS_NAM) > 50 THEN 5
ELSE 'some value'
END AS A_VAL
FROM
TABLE1 t
JOIN IWD t1 ON(t.A_INS_NAM = t1.A_INS_NAM)
JOIN TIM t2 ON(t1.IWD = t2.IM_ID)
JOIN TWS t3 ON(t2.IM_ID = t3.T_ID )
WHERE t3.TN = 'abced'
AND t.A_DATE BETWEEN '2014-01-01' AND '2015-05-01'
AND t.A_INS_NAM NOT LIKE '%pk%'
GROUP BY t.A_DATE

Coalesce whole records in MySQL

I'm currently coallescing fields individually in MySQL queries, but I would like to coalesce whole records.
Is this possible?
SELECT la.id,
COALESCE(( SELECT name FROM lookup_changed l0,
( SELECT MAX(id) id
FROM lookup_changed
WHERE lookup_id = 26
) l1
WHERE l0.id = l1.id
), la.name) name,
COALESCE(( SELECT msisdn FROM lookup_changed l0,
( SELECT MAX(id) id
FROM lookup_changed
WHERE lookup_id = 26
) l1
WHERE l0.id = l1.id
), la.msisdn) msisdn
FROM lookup_added la
WHERE la.id = 26
#Alma Do - the pseudo-SQL is:
SELECT la.id,
MULTICOALESCE(( SELECT <name, msisdn> FROM lookup_changed l0,
( SELECT MAX(id) id
FROM lookup_changed
WHERE lookup_id = 26
) l1
WHERE l0.id = l1.id
), <la.name, la.msisdn>) <name, msisdn>
FROM lookup_added la
WHERE la.id = 26
Since COALESCE() "return[s] the first non-NULL argument", it sounds like you want to retreive the "first non-NULL result from a set for queries":
-- syntax error
SELECT COALESCE(
SELECT a FROM ta,
SELECT b FROM tb
);
-- roughly equates to
( SELECT a AS val FROM ta WHERE a IS NOT NULL ORDER BY a LIMIT 1 )
UNION
( SELECT b AS val FROM tb WHERE b IS NOT NULL ORDER BY b LIMIT 1 )
ORDER BY val LIMIT 1 ;
Comments:
I added ORDER BY clauses, otherwise "first row" means nothing
the inner LIMIT 1 clauses are optional (but allow early trimming of sub-results)
the parenthesis around the sub queries are mandatory

How do I select random rows in MySQL?

mytable
pid name field
=== ==== =====
1 A1 0
2 A2 1
3 A3 1
4 A4 0
5 A5 0
This is my table structure. Here I want to select randomly 4 rows so I use RAND() mysql function in my query
my questions is
How do I pair to rows. I mean, I wanna select pid 2 and 3 always one ofter another.
I need in bellow order. i don't want to break the pair A2 A3
A1 A2 A3 A4 or A2 A3 A4 A1 or A2 A3 A4 A5 or A4 A5 A2 A3 and etc
I used the query below but it's not working for me
SELECT * FROM mytable ORDER BY RAND() ASC limit 0,4
turbod was close with his answer, he was just ordering randomly, when it seems you wanted to order by pid, after getting the random rows you wanted in conjunction with the ones concerning A2 and A3:
(
SELECT *
FROM `mytable`
WHERE
name ='A2' OR
name ='A3'
LIMIT 2
)
UNION
(
SELECT DISTINCT *
FROM `mytable`
WHERE
name !='A2' OR
name !='A3'
ORDER BY RAND( ) LIMIT 2
)
ORDER BY `pid`
Generally, using ORDER BY RAND() is not a good idea. Please read the text by Jan Kneschke, showing why: http://jan.kneschke.de/projects/mysql/order-by-rand/
I ran a heavy test on this, passed.
(
SELECT * , 0.5 AS ordercol
FROM `mytable`
WHERE `name`IN ( "A2", "A3" )
LIMIT 2
)
UNION (
SELECT * , rand() AS ordercol
FROM `mytable`
WHERE `name` NOT IN ( "A2", "A3" )
LIMIT 2
)
ORDER BY ordercol, `name` IN ( "A2", "A3" ) , `name` ="A3"
This will do the job very well. But to make the result even more random, execute that statement with replacing that 0.5 value in 1st line with a random value chosen by your client application code like mt_rand(0, 1000000) / 1000000 in PHP . Make sure it falls between 0 and 1. But do NOT use mysql function rand() in place of that 0.5 because it will make A2 and A3 apart from each other. The trick is assigning a random value for "ordercol" in all rows but keep it same for A2 and A3
EDIT:
I believe we can replace the 0.5 value with a LEFT JOIN even instead of relying on discrete value by PHP, as we replace the first segment of the union, so the whole query becomes:
(
SELECT mt1.* , mt2.ordercol AS ordercol
FROM `mytable` AS mt1
LEFT JOIN (
SELECT RAND( ) AS ordercol
) AS mt2 ON TRUE
WHERE `name`
IN (
"A2", "A3"
)
LIMIT 2
)
UNION (
SELECT * , rand() AS ordercol
FROM `mytable`
WHERE `name` NOT IN ( "A2", "A3" )
LIMIT 2
)
ORDER BY ordercol, `name` IN ( "A2", "A3" ) , `name` ="A3"
I doubt there is a sane way to this in MySQL only.
I can think of one way of doing it, assuming you are using PHP/MySQL:
Essentially you query everything but A3, then put A3 next to A2
$res = mysql_query("SELECT name, field FROM mytable WHERE name <> 'A3' ORDER BY RAND()");
$res2 = mysql_query("SELECT name, field FROM mytable WHERE name = 'A3'");
$data = array();
while($row = mysql_fetch_array($res))
{
array_push($data, $row);
if ($row['name'] == "A2")
{
$row2 = mysql_fetch_array($res2);
array_push($data, $row2);
}
}
Now $data will contain your results in the desired order.
If you are always selecting all the rows in the table:
SELECT pid, name, field, idx
FROM (
SELECT pid, name, field,
#pos := IF(name = 'A3', #idx, #pos),
#idx := #idx + IF(name = 'A3', 2, 1), idx
FROM mytable, (SELECT #pos = -1, #idx := 0) dm
WHERE name <> 'A2'
ORDER BY RAND()
)
UNION SELECT pid, name, field, #pos + 1 idx
FROM mytable
WHERE name = 'A2'
ORDER BY idx;
If you are not always returning all the rows, thus need to check if A3 was returned to know if A2 should be included:
SELECT pid, name, field, idx
FROM (
SELECT pid, name, field,
#pos := IF(name = 'A3', #idx, #pos),
#idx := #idx + IF(name = 'A3', 2, 1), idx
FROM mytable, (SELECT #pos = -1, #idx := 0) dm
WHERE name <> 'A2'
ORDER BY RAND()
LIMIT 4
)
UNION SELECT pid, name, field, #pos + 1 idx
FROM mytable
WHERE #pos != -1 AND name = 'A2'
ORDER BY idx;
SELECT * FROM (
SELECT DISTINCT name FROM mytable
WHERE name <> 'A2' AND name <> 'A3'
ORDER BY RAND()
LIMIT 0,2
UNION
SELECT DISTINCT name FROM mytable
WHERE name = 'A2' OR name = 'A3'
ORDER BY name
)whateverQueryAlias
ORDER BY RAND()
That should do it.
Here is my solution:
SELECT *
FROM `mytable`
WHERE name ='A2'
OR name ='A3'
LIMIT 2
UNION
(SELECT DISTINCT *
FROM `mytable`
WHERE name !='A2'
OR name !='A3'
ORDER BY RAND( ) LIMIT 2) ORDER BY RAND()
SELECT *, RAND() "xrand" FROM yourtable A ORDER BY xrand LIMIT 4
SELECT * FROM `mytable` order by rand(), name asc limit 4.
i think this will satisfy your need.