I have the following table:
table A
id emp emp_dst
1 a b
2 a d
3 b c
4 b a
5 c d
6 d a
7 d b
8 d c
my sql query should return me the following simplified table since a = b equals b = a
table B
emp emp_dst
a b
a d
b c
d b
d c
but I have no idea how to do this in an sql query in MYSQL,
try revising expressions with UNION but the results are wrong
An alternative that suits my personal preferences better...
(Based on your comment that the id in the results was not relevant.)
SELECT
CASE WHEN emp <= emp_dst THEN emp ELSE emp_dst END AS emp,
CASE WHEN emp <= emp_dst THEN emp_dst ELSE emp END AS emp_dst
FROM
yourTable
GROUP BY
1, 2
ORDER BY
1, 2
If you want an id, then you can add MIN(id). Just note that the id found may actually have the two values the other way around.
An alternative that uses a LEFT JOIN rather than GROUP BY.
SELECT
yourTable.*
FROM
yourTable
LEFT JOIN
yourTable AS reflection
ON reflection.emp_dst = yourTable.emp
AND reflection.emp = yourTable.emp_dst
AND reflection.id <> yourTable.id
WHERE
(reflection.id IS NULL)
OR (yourTable.emp < reflection.emp_dst)
OR (yourTable.emp = reflection.emp_dst AND yourTable.id < reflection.id)
ORDER BY
yourTable.emp,
yourTable.emp_dst
(The last OR is only needed if a table can have 'a', 'a', and it appear twice.)
Note: This may benefit from having two indexes...
CREATE INDEX yourTable_e_ed_id ON yourTable( emp, emp_dst, id );
CREATE INDEX yourTable_ed_e_id ON yourTable( emp_dst, emp, id );
Related
I have 2 tables
LoanApplications (Id, Name, CreationDate, LoanApplicationStatusId)
Positions(Id, Name, CreationDate, LoanApplicationId)
I need to find all loan applications that have more than 1 position and update LoanApplicationStatusId to 2
I write code to get these LoanApplications like this
SELECT e.Id, count(Name) FROM LoanApplications e
INNER JOIN Positions d ON e.Id=d.LoanApplicationId
GROUP BY e.Id
HAVING COUNT(Name)>1
But I don't understand how to make an update now.
Can you help me?
Straight ahead would be a simple subselect
UPDATE LoanApplications l
SET LoanApplicationStatusId = 2
where (select count(1) from Positions p where p.LoanApplicationId = l.id) > 1
Simply select id of apps which have more than one row, and use it in UPDATE as a condition
UPDATE LoanApplications
JOIN ( SELECT LoanApplicationId
FROM Positions
GROUP BY LoanApplicationId
HAVING COUNT(LoanApplicationId) > 1 ) multi_positional ON id = LoanApplicationId
SET LoanApplicationStatusId = 2
Unsafe query: 'Update' statement without 'where' updates all table rows at once Got this stuff – Eugene Sukh
Convert this query to
UPDATE LoanApplications
JOIN ( SELECT LoanApplicationId
FROM Positions
GROUP BY LoanApplicationId
HAVING COUNT(LoanApplicationId) > 1 ) multi_positional
SET LoanApplicationStatusId = 2
WHERE LoanApplications.id = multi_positional.LoanApplicationId
Here is the table called flight info.
departure arrival
A B
C A
A C
C A
B C
C D
D B
A C
B A
The out put should be:
departure Arrival
A B
A C
B C
C D
D B
I try to use GROUP BY on both columns. However, I cannot find a way to identify same letters but in different order at two columns. Please help me out. Thank you so much and I appreciate it.
[I prefer MYSQL solution]
select distinct
case when departure<=arrival then departure else arrival end as X,
case when departure> arrival then departure else arrival end as Y
from T
you can use below query
First I concat both column with condition
SELECT departure,arrival,
CASE WHEN departure>arrival THEN CONCAT(arrival,departure) ELSE CONCAT(departure,arrival) END c
FROM t1
ORDER BY c
then select the first column if data has A,B and B,A. This will select A,B and next row return null. Like ranking
SELECT departure,arrival,#winrank := IF( #cvalue=NULL ,c, IF(#cvalue=c,NULL,c)) AS r ,
#cvalue :=c AS r1
FROM (
SELECT departure,arrival,
CASE WHEN departure>arrival THEN CONCAT(arrival,departure) ELSE CONCAT(departure,arrival) END c
FROM t1
ORDER BY c) t , (SELECT #cvalue :=NULL) r
And the final query is
SELECT departure,arrival FROM (
SELECT departure,arrival,#winrank := IF( #cvalue=NULL ,c, IF(#cvalue=c,NULL,c)) AS r ,
#cvalue :=c AS r1
FROM (
SELECT departure,arrival,
CASE WHEN departure>arrival THEN CONCAT(arrival,departure) ELSE CONCAT(departure,arrival) END c
FROM t1
ORDER BY c) t , (SELECT #cvalue :=NULL) r) f
WHERE f.r IS NOT null
One method is:
select distinct arrival, departure
from t
where arrival < departure or
not exists (select 1
from t t2
where t2.arrival = t.departure and t2.departure = t.arrival
);
Here is a db<>fiddle
The first condition selects all rows where the arrival is smaller than the departure. The second adds in the pairs where the inverse is not in the table.
I have a list of products identified by their SKUs. To simplify it, I just name them as A, B, C, D,... here. Each of these SKUs has been assigned by default an already existing GroupID, for simplicity I just number them as 1, 2, 3,... here.
The same GroupID would mean "These SKUs are equivalent, so it is ok to use/buy either one of them, as it makes no difference".
The problem is, some SKUs show up more than once as they come from a different buying source, but as they come from a different source, they have a different grouping.
The goal is therefore to consolidate the grouping and make sure they have the same groupings.
I already apologize if my illustration may not be super pretty, but I'm trying. Here's a small data table sample on how the raw data looks like (first line is the column names):
Source SKU GroupID
Seller1 A 1
Seller1 B 1
Seller1 C 1
Seller2 B 2
Seller2 D 2
Seller2 E 2
Seller3 A 3
Seller3 B 3
Seller4 F 4
Seller4 G 4
Seller4 H 4
The result should be like:
Source SKU GroupID
Seller1 A 1
Seller1 B 1
Seller1 C 1
Seller2 B 1
Seller2 D 1
Seller2 E 1
Seller3 A 1
Seller3 B 1
Seller4 F 4
Seller4 G 4
Seller4 H 4
Basically, if Any SKU in GroupID X is a subset of GroupID Y, then GroupID Y = GroupID X. But that should be applied on all GroupIDs, so it appears to be recursive.
I wish I could show the code that I tried already and I tried already for a few days, but I literally only managed to produce garbage.
In C# I'd know how to deal with this, but I can't seem to wrap my head around SQL as I am not that experienced and unfortunately I would need this in SQL.
I would be thankful for any kind of help, even if it's just a hint or direction you guys would suggest I should try. Thanks a lot!
You want a correspondence between groups, which you can calculate with a recursive CTE:
with recursive tt as (
select distinct t1.groupid as groupid1, t2.groupid as groupid2
from t t1 join
t t2
on t1.sku = t2.sku
),
cte as (
select tt.groupid1, tt.groupid2, concat_ws(',', tt.groupid1, tt.groupid2) as visited
from tt
union all
select cte.groupid1, tt.groupid2, concat_ws(',', visited, tt.groupid2)
from cte join
tt
on cte.groupid2 = tt.groupid1
where find_in_set(tt.groupid2, cte.visited) = 0
)
select groupid1, min(groupid2) as overall_group
from cte
group by groupid1;
You can then join this back to the original table to get the "overall group":
with recursive tt as (
select distinct t1.groupid as groupid1, t2.groupid as groupid2
from t t1 join
t t2
on t1.sku = t2.sku
),
cte as (
select tt.groupid1, tt.groupid2, concat_ws(',', tt.groupid1, tt.groupid2) as visited
from tt
union all
select cte.groupid1, tt.groupid2, concat_ws(',', visited, tt.groupid2)
from cte join
tt
on cte.groupid2 = tt.groupid1
where find_in_set(tt.groupid2, cte.visited) = 0
)
select t.*, g.overall_group
from t join
(select groupid1, min(groupid2) as overall_group
from cte
group by groupid1
) g
on t.groupid = g.groupid1;
Here is a db<>fiddle.
Note: Your sample data is rather "complete" so you don't need a recursive CTE for that particular data. However, I am guessing that your real groups have a bit less overlap in which case recursion is necessary.
First is to get all those sellers with subsets based on count. then filter using Group By
select table1.Source, SKU, case when table1.Source = t6.Source and t6.cnt > 1 then 1 else 2 end as GroupID
from table1
left join
(select t5.Source, count(t5.cnt) as cnt from (
select distinct t4.Source, t4.cnt from (
select t3.Source, count(t3.SKU) as cnt from (
select t1.Source, t1.SKU from table1 t1
left join table1 t2 on t2.SKU = t1.SKU ) t3
group by t3.Source, t3.SKU
order by t3.Source) t4) as t5
group by t5.Source) t6 on t6.Source = table1.Source
I have three tables, A,B and C
Tables A and B have an ID and other fields, table C is a n-n relationship of A and B (C contains only IDS of A and B with primary key(id_a, id_b) and foreign key).
Now I need to verify if a row of A has the same associations of another row of A.
EXAMPLE
A = [id_a] = [1,2,3,4]
B = [id_b] = [1,2,3,4]
C = [id_a, id_b] = [[1,1],[1,3],[2,1],[2,3],[3,3]]
In this case, I need to extract only records where id_a are 1 and 2, because they are both associated with the same row of B (id_b 1 and 3).
id_a=3 is not the same as id_a=1/2, because it isn’t associated with id_b=1
This is for a new Ubuntu 18.04 server, running MySQL, PHP 7 (LAMP stack)
Example with id_a=1
SELECT id_a
FROM C
WHERE id_b IN (SELECT id_b FROM B WHERE id_a=1)
GROUP BY id_a;
The simplest method for an exact match uses group_concat():
select c.id_a
from (select c.id_a, group_concat(c.id_b order by c.id_b) as id_bs
from c
group by c.id_a
) c join
(select group_concat(c.id_b order by c.id_b) as id_bs
from c
where c.id_a = #id_a
) ac
on c.id_bs = ac.id_bs
I am trying to run a select statement on two different servers that have some matching primary keys. I want to be able to select the primary key but add the prefix 'A' to every record
ex:
ID "to this" ID
1 A1
2 A2
3 A3
This is what I have for the query
select 'A' + CAST (a.id AS VARCHAR(25)) as ID,a.*,':', b.*,':',c.*,':', d.*,':', e.*,'REPORTDT', g.*
from labgen.order_ a
join patient b on a.id = b.chart
join insurance c on b.ins1 = c.code
join client d on d.num = a.client1
join salesgrp e on d.salesgroup = e.num
join reportdt g on a.accession = g.accession
Try this in the select statement:
select CONCAT('A', a.id) as ID, a.*,':', //etc
This link will also help.