how can you eliminate permutations between columns in MySQL - mysql

i have table columns one (idprocess) point to columns two (idporcess1) and point to columns tree (idprocess2).
id idprocess idporcess1 idprocess2
1 15 16 17 <== A
2 15 16 19 <== B
3 15 20 23
4 14 16 17
6 16 15 80 <== C
7 17 15 49 <== D
8 23 16 20 <== E
I need a SQL query that returns this: row c and row D, so with number idprocess(16) and idprocess(17 )
because row c : idprocess(16) references again ipdprocess1(15)
because row c : idprocess(17 ) references agin ipdprocess1(15)
please help
i want only to eleminate circular referencial in tree

If you are happy to find rows where the first two columns are permutated, this will do the job:
SELECT *
FROM my_tbl t
WHERE EXISTS (SELECT 1 FROM my_tbl t1 WHERE t1.idprocess = t.idprocess1 AND t1.idprocess1 = t.idprocess)
ORDER BY t.id;
Alternative interpretation:
If you want all rows where idprocess1 has been listed in idprocess before (before = smaller id), then you can:
SELECT *
FROM my_tbl t
WHERE EXISTS (SELECT 1 FROM my_tbl t1 WHERE t1.id < t.id AND t1.idprocess = t.idprocess1)
ORDER BY t.id;
You wouldn't call that "permutation", though.

The question is a bit ambiguous but I tried to understand it on my own and prepared the following query:
SELECT *
FROM TEMP
where C2 IN ( Select C2 FROM TEMP group by C2 having count(C2) > 1 )
OR C3 IN ( Select C3 FROM TEMP group by C3 having count(C3) > 1 )

Related

MySQL join and group based on date ranges

I have table A
uid dt val_A
10 04/09/2012 34
10 08/09/2012 35
10 10/09/2012 36
100 04/09/2012 40
100 08/09/2012 41
and table B
uid date val_B
10 04/09/2012 1
10 05/09/2012 1
10 06/09/2012 2
10 07/09/2012 2
10 08/09/2012 1
100 07/09/2012 1
100 07/09/2012 3
I want to join them to get table C. I want to join them on uid. Furthermore I want to have a new column val_C which holds the average of val_B where date in B is greater or equal than the corresponding row-value dt in A AND less than the next higher dt value for this uid in table A. It means I want to aggregate the values in B based on date ranges defined in A. The joined table should look like this:
uid dt val_A val_C
10 04/09/2012 34 1.5
10 08/09/2012 35 1
10 10/09/2012 36 0
100 04/09/2012 40 2
100 08/09/2012 41 0
How can this be achieved?
//EDIT
How could a more generalized solution look like where all dates in B2 which are greater than the greatest date in A are being joined & aggregated to the greatest date in A. B2:
uid date val_B
10 04/09/2012 1
10 05/09/2012 1
10 06/09/2012 2
10 07/09/2012 2
10 08/09/2012 1
100 07/09/2012 1
100 07/09/2012 3
100 10/09/2012 4
100 11/09/2012 2
Desired output C2:
uid dt val_A val_C
10 04/09/2012 34 1.5
10 08/09/2012 35 1
10 10/09/2012 36 0
100 04/09/2012 40 2
100 08/09/2012 41 3
If you're on MySQL v8+ that supports LEAD() function, then you can try this:
WITH cte AS (
SELECT uid, dt, val_A,
IFNULL(LEAD(dt) OVER (PARTITION BY uid ORDER BY uid, dt),dt) dtRg
FROM tableA)
SELECT cte.uid, cte.dt, cte.val_A,
AVG(val_B) AS val_C
FROM cte
LEFT JOIN tableB tb1
ON cte.uid=tb1.uid
AND tb1.dt >= cte.dt
AND tb1.dt < cte.dtRg
GROUP BY cte.uid, cte.dt, cte.val_A
The query in common table expression (cte):
SELECT uid, dt, val_A,
IFNULL(LEAD(dt) OVER (PARTITION BY uid ORDER BY uid, dt),dt) dtRg
FROM tableA
will give you a result like this:
As you can see, the dtRg column is generated using LEAD() function which takes the next row dt value according to the ORDER BY. Read more about LEAD() here.
After that, join the cte with tableB on matching uid and where tableB.dt is the same or bigger than the existing tableA.dt - which is now as cte.dt, but lower than cte.dtRg - which is the next date in tableA that was generated by LEAD(). And finally adding AVG(val_B) AS val_C
Demo fiddle
On older MySQL version, you can try this:
SELECT tA.uid, tA.dt, tA.val_A,
AVG(val_B) AS val_C
FROM
(SELECT uid, dt, val_A,
(SELECT dt FROM tableA ta1
WHERE ta1.uid=ta2.uid
AND ta1.dt > ta2.dt LIMIT 1) AS dtRg
FROM tableA ta2) tA
LEFT JOIN tableB tB
ON tA.uid=tB.uid
AND tB.dt >= tA.dt
AND tB.dt < tA.dtRg
GROUP BY tA.uid, tA.dt, tA.val_A;
The difference are as following:
Instead of using LEAD(), it uses correlated subquery in SELECT to get the next dt value of next row in the same uid.
Instead of common table expression, it uses a derived table.
Fiddle for MySQL v5.7 version

Select rows in SQL that follow certain conditions

I want to select rows that follow the following conditions in SQL.
Table Name:
Codes_and_Numbers
I have the following dataset:
Code_Name Num_1 Num_2
A 10 12
A 10 10
A 10 10
B 17 17
B 17 17
B 17 17
B 17 17
C 21 25
C 21 23
I want to select the rows where Num_1 and Num_2 are not equal, however if on another row with the same Code_Name, Num_1 and Num_2 are equal then I don't want to select any of the rows under that Code_Name.
In the dataset above, this would mean only the 2 rows for C would be selected. As A has two rows with equal Num_1 and Num_2 and all of B rows are equal.
You can use NOT EXISTS:
SELECT Code_Name, Num_1, Num_2
FROM Codes_and_Numbers AS t1
WHERE t1.Num_1 <> t1.Num_2 AND
NOT EXISTS (SELECT 1
FROM Codes_and_Numbers AS t2
WHERE t1.Code_Name = t2.Code_Name AND
t2.Num_1 = t2.num_2)

Group by adjacent rows based on two columns

Let's say I have a table like this:
id col1 col2
---------------------
1 35 A
2 40 B
3 39 B
4 39 B
5 39 B
6 40 B
7 39 B
8 39 B
9 40 B
10 40 C
11 35 C
How do I make it so that it has a result like this:
id col1 col2
---------------------
1 35 A
2 40 B
3 39 B
6 40 B
7 39 B
9 40 B
10 40 C
11 35 C
I want to group by col1 that has same value in adjacent rows while also has same group in col2 (col1 values in id:9 and id:10 couldn't be grouped because it has different col2 value)
Any help would be appreciated, thanks!
The key idea is to get a grouping identifier for the adjacent rows. The question is: what characteristic of the rows is constant for rows that should be grouped together?
Well, here is one: the number of previous rows (based on id) that have different values in either col1 or col2 is the same for all rows in a group.
You can turn this observation into a measure for each row (using a correlated subquery). The rest is just aggregation:
select min(id) as id, col1, col2, count(*) as NumInGroup
from (select t.*,
(select count(*)
from t t2
where t2.id < t.id and (t2.col1 <> t.col1 or t2.col2 <> t.col2)
) as grp
from t
) t
group by grp, col1, col2;
demo: db-fiddle
Note: This will work well-enough on small amounts of data, but it does not scale particularly well.

How to delete duplicate data with a condition

I have witten a query to delete the duplicate data
DELETE FROM tbl_test t
WHERE t.ROWID > ANY (SELECT b.ROWID
FROM tbl_test b
WHERE b.ser_no = t.ser_no
);
This gives me 199 records which is correct .
Since the duplicate records have status L,F or R . So I have to delete all teh records which are F or R.
For example if I have two records
ID ser_no Sta
1 20 L
2 20 F
3 15 R
4 15 L
5 89 L
6 89 F
7 10 R
8 10 R
So only one of the duplicate of Status R or F should be Deleted . There is no case in which both dupliate has LL or F,R Status
So I tried
DELETE FROM tbl_test t
WHERE t.ROWID > ANY (SELECT b.ROWID
FROM tbl_test b
WHERE b.ser_no = t.ser_no
AND b.Sta<>'L'
);
It did not work. It displays 125 records.
The final result should be
ID ser_no Sta
2 20 F
3 15 R
6 89 F
8 10 R
Try this delete statement, it works as described in rules and gave correct output for your examples:
SQLFiddle
delete from tbl_test t
where t.sta in ('F', 'R') and exists (
select 1 from tbl_test b
where b.ser_no = t.ser_no
and (sta='L' or (sta<>'L' and b.id<t.id)) )
try this query
DELETE FROM tbl_test t
WHERE t.ROWID in (SELECT max(b.ROWID)
FROM tbl_test b
where b.Sta in('R','F')
group by b.ser_no,b.Sta
);

combine two columns in 1 column mysql

i have tablea and table b
tablea :
Nama Jumlah
A 66
B 95
C 47
E 57
F 52
tableb:
Nama Jumlah Gaji
A 35 47
B 28 51
C 18 24
D 27 30
E 30 29
G 31 16
how to make query that can combine two tables in one table an to be like this
result :
Nama Jumlah Gaji
A 101 47
B 123 51
C 65 24
D 27 30
E 87 29
F 52 0
G 31 16
it's my query. but i can't get the the result like that.
SELECT a.nama, (a.jumlahtotala+b.jumlahtotalb) AS Jumlah FROM (SELECT nama, SUM(jumlah) AS jumlahtotala FROM tablea GROUP BY nama) a JOIN (SELECT nama, SUM(jumlah) AS jumlahtotalb, SUM(gaji) AS gaji FROM tableb GROUP BY nama) b GROUP BY a.name
thanks for your help
EDITED
Sorry for another question in comment
Try joining the two tables like:
SELECT b.Nama, IFNULL(a.Jumlah, 0) + b.Jumlah, b.Gaji
FROM tablea a RIGHT JOIN tableb b
ON a.Nama = b.Nama
If Nama is not unique in tablea or tableb, or if rows exist in tablea that don't have a matching row in tableb, for example:
tablea:
Nama Jumlah
A 66
B 95
C 47
C 18
tableb:
Nama Jumlah Gaji
A 35 47
C 0 24
D 27 30
Z NULL 99
If an acceptable result is to return a single occurrence of each value of Nama along with the totals of Jumlah and Gaji, then one approach (assuming the datatypes of the Nama and Jumlah columns is compatible), and assuming that there isn't a requirement to return the rows in a particular sequence, one option is to combine the two sets with a UNION ALL operator into a derived table, and then use SUM() aggregate.
For example:
SELECT t.Nama
, SUM(t.Jumlah) AS Jumlah
, SUM(t.Gaji) AS Gaji
FROM ( SELECT b.Nama
, b.Jumlah
, b.Gaji
FROM tableb b
UNION ALL
SELECT a.Nama
, a.Jumlah
, NULL
FROM tablea a
) t
GROUP BY t.Nama
Because of the derived table (i.e. the way that MySQL processes derived tables), this will likely not be the most efficient approach for large sets.