Sort multiple query results in a single query - sql

I have a select statement returning 5 columns:
select col1,col2,col3,col4,col5 from table1;
col1 col2 col3 col4 col5
9 A B C D
8 E F G H
I have another select statement from table2 which returns col1 alone;
col1
8
9
Based on the two select queries, is there a way to write a single select query to return the result as:
col1 col2 col3 col4 col5
8 E F G H
9 A B C D
ie. basically sort the output of I query based on col1 from II query. (this is in Mysql)
PS:II table column1 is used to for sorting & that is coming from table 2. Table2's col1 is not static, its changing for every user action & based on a call i will get col1 of table 2 & need to sort with table1's output.

Use an ORDER BY:
SELECT col1,col2,col3,col4,col5
FROM table1
ORDER BY col1
By default, ORDER BY is ASC.
SELECT col1,col2,col3,col4,col5
FROM table1
ORDER BY col1 DESC
...will put 9 from col1 as the first record returned.

For this to work, you seriously need a sort column on table2. Just having the IDs in table2 is not enough. You can have the records 7,8,9, then delete 8 and add it back. But no, that doesn't order it as 7,9,8. Maybe temporarily if there is no primary key on the table, but when the table gets large, even that "implicit" order is lost.
So, assuming you have such a sort column
Table2
Sort, Col1
1, 9
2, 8
Your query becomes
SELECT a.*
FROM table1 a
INNER JOIN table2 b ON a.col1 = b.col1
ORDER BY b.sort ASC
If you still want to rely on MySQL undocumented features or the way it currently works, then you can try this.
# test tables
create table table1 (col1 int, col2 int, col3 int);
insert table1 select 8, 1,2; # in this order
insert table1 select 9, 3,4;
create table table2 (col1 int);
insert table2 select 9; # in this order
insert table2 select 8;
# select
SELECT a.*
FROM table1 a
INNER JOIN table2 b ON a.col1 = b.col1
----output----
col1 col2 col3
9 3 4
8 1 2
This works at least for small tables, only because size(table2) < size(table1) so it collects in that order, preserving the filesort on table2.col1.

Not sure what the relationship is between t1.col1 and t2.col2. Probably looking for something like this though:
SELECT t2.col1, t1.col2, t1.col3, t1.col4, t1.col5
FROM table2 t2
INNER JOIN table1 t1 ON t1.col1 = t2.col1
ORDER BY t2.col1 ASC

Related

Need help finding duplicate values for Data Quality checks

I have a table which requires me to ensure that a combination of attributes should have a unique record against it.
col1 col2 col3
a b x
a b y
a c x
a d z
e b w
How do I ensure that a col1+col2 combination only has unique col3 values. Here ab has both x and y as col3 values. I have to send such rows to a reject file and I am looking for the right filter query.
We can use an aggregation approach. To identify rows which are failing the unique requirement use:
WITH cte AS (
SELECT col1, col2
FROM yourTable
GROUP BY col1, col2
HAVING MIN(col3) <> MAX(col3)
)
SELECT t1.*
FROM yourTable t1
INNER JOIN cte t2
ON t2.col1 = t1.col1 AND
t2.col2 = t1.col2;

To reverse column values

I have two column given below
col1 col2
1 a
2 b
3 c
4 d
and my expected output is
col1 col2
1 d
2 c
3 b
4 a
One approach is to use subquery and self join with condition t1.col1+t2.col1=max(col1)+min(col1) which will enforce to have last value of t2 to be in same row with the first value of t1. But this approach will only work if you have sequential numbers without any gap in sequence.
If the number is always in proper sequence this can be faster in performance.
And another approach is with row_number(). You can have your data both in ascending and descending order then join them on their rownumber column and select col1 from ascending order and col2 from descending order.
This will be better approach if your dbms supports this, since any gap in the sequence is accepted here.
Schema:
create table test (col1 int, col2 varchar(10));
insert into test values(1 , 'a');
insert into test values(2 , 'b');
insert into test values(3 , 'c');
insert into test values(4 , 'd');
Query#1 with subquery and self join:
select t1.col1, t2.col2
from test t1 join
test t2
on t1.col1 + t2.col1 =(select max(col1)+min(col1) from test)
order by t1.col1
Output:
col1
col2
1
d
2
c
3
b
4
a
Query#2 with row_number()over():
select t1.col1,t2.col2 from
(select col1,col2,row_number()over(order by col1)rn from test)t1
inner join (select col1,col2,row_number()over(order by col1 desc)rn from test)t2
on t1.rn=t2.rn
output:
col1
col2
1
d
2
c
3
b
4
a
db<>fiddle here
For your given data, you can use a self-join:
select t.col1, t2.col2
from t join
t t2
on t2.id = 5 - t.id ;
This does not generalize particularly well.

Filter rows if value in one column exists in another column

I have following table in Postgres 11:
col1 col2 col3 col4
1 trial_1 ag-270 ag
2 trial_2 ag ag
3 trial_3 methotexate (mtx) mtx
4 trial_4 mtx mtx
5 trial_5 hep-nor-b nor-b
I would like to search each value of col4 throughout the column col3. If the value in col4 exists in col3, I would like to keep the rows else the row should be excluded.
Desired output is:
col1 col2 col3 col4
1 trial_1 ag-270 ag
2 trial_2 ag ag
3 trial_3 methotexate (mtx) mtx
4 trial_4 mtx mtx
I could not try anything on this as I am unable to find a solution to this yet.
If the value in col4 exists in col3, I would like to keep the rows.
... translates to:
SELECT *
FROM tbl a
WHERE EXISTS (SELECT FROM tbl b WHERE b.col3 = a.col4);
db<>fiddle here
Produces your desired result.
This can be done as an inner join:
select distinct t.col1, t.col2, t.col3, t,col4
from T t inner join T t2 on t2.col3 = t.col4
select a.*
from myTable a
where exists (
select 1
from myTable b
where b.col3 = a.col4)
If your table has many rows, you should ensure that col3 is indexed.

copy a table into a new table and add a new column on SQL server 2008

I need to copy a table into a new table on SQL server 2008.
Also, add a new column into the new table.
The values of the new column depends on the compare result between the new table and another table.
Example,
Table1:
col1 col2 col3
abc 346 6546
hth 549 974
Expected Table1_new:
col1 col2 col3 col4
abc 346 6546 1
hth 549 974 0
Table2:
col1
abc
sfsdf
If Table2's col1 appear in Table1 col1, mark col4 as 1 in Table1_new, else mark as 0.
The code does not work
SELECT *,
(
SELECT 1 as col4
FROM Table2 as a
INNER JOIN Table1 as b
on b.col1 = a.col1
SELECT 0 as col4
FROM Table2 as a
INNER JOIN Table1 as b
on b.col1 <> a.col1 # I do not know how to do this !!!
)
INTO table1_new
FROM table1
Any help would be appreciated.
You could use an outer join:
SELECT table1.col1, col2, col3,
CASE WHEN table2.col1 IS NULL THEN 0 ELSE 1 END AS col4
INTO table1_new
FROM table1
LEFT OUTER JOIN table2 ON table1.col1 = table2.col1
You can do this in several ways. The following uses an exists clause in a case statement:
insert into table1_new(col1, col2, col3, col4)
select col1, col2, col3,
(case when exists (select 1 from table2 t2 where t2.col1 = t1.col1)
then 1 else 0
end)
from table1 t1;
You can also do this with a left outer join, but you run the risk of duplicates if t2 has duplicates.
INSERT INTO T2
SELECT COL1,COL2,COL3, (COL1+COL2) FROM T1
Note that instead of the (COL1+COL2) section you could run other expressions or possibly even a function.
Try something like this using CASE
SELECT
CASE
WHEN b.col1 = a.col1 THEN 1
ELSE 0
END as col4
FROM Table1 as a
LEFT JOIN Table2 as b
on b.col1 = a.col1
EDIT: Table1 should be the left table as mentioned in #Muerniks answer.
In addition to what the others already suggested: If you can't solve the problem in one step, try to make smaller steps. E.g. first initialize Table1.col4 with zero:
INSERT INTO Table1_new (col1,col2,col3,col4)
SELECT col1,col2,col3,0
FROM Table1
After that you will only need to identify the records which have matching partners in Table2 which is a classical inner join:
UPDATE t1 SET col4=1
FROM Table1_new t1
JOIN Table2 t2 ON t2.col1=t1.col1

Join Tables SQL Server with duplicates

I have a table
col1
1
2
and other table
col1 col2 col3
1 1 data value one
1 2 data value one
2 3 data value two
and I want to join both tables to obtain the following result
col1 col2 col3
1 1 data value one
2 3 data value two
The second table have duplicates but I need to join only one (randomly). I've tried with Inner Join, Left Join, Right Join and always returns all rows. Actually I use SQL Server 2008.
select t1.col1, t2.col2, t2.col3 from table1 t1
cross apply
(select top 1 col2, col3 from table2 where col1 = t1.col1 order by newid()) t2
You can use the ROW_NUMBER Function along with ORDER BY NEWID() To get one random row for each value in col1:
WITH CTE AS
( SELECT Col1,
Col2,
Col3,
[RowNumber] = ROW_NUMBER() OVER(PARTITION BY Col1 ORDER BY NEWID())
FROM Table2
)
SELECT *
FROM Table1
INNER JOIN CTE
ON CTE.Col1 = table1.Col1
AND CTE.RowNumber = 1 -- ONLY GET ONE ROW FOR EACH VALUE
Use Distinct it will eliminate dups, but you sure both rows will contain same data?