SQL Join 2 tables without a relation - sql

Let's say I have the following tables:
Table1 with cols: A, B
Table2 with col: C
And I have a variable #d.
|Table1| |Table2| #d = 5;
------ ------
|A | B| | C |
------- -------
a1 | b1 c1
a2 | b2 c2
How can I display following output?
| ResultTable |
------------------
|A | B | C | d|
a1 b1 c1 5
a2 b2 c2 5
PS: I am using T-SQL.

You can use row_number to give each row a number and join on that. This assumes both tables have the same # of rows.
select *, #d from (
select *, row_number() over (order by A) rn
from Table1
) t1 join (
select *, row_number() over (order by C) rn
from Table2
) t2 on t1.rn = t2.rn

Related

Delete almost duplicates in a table

I have a table where strings 1 and 2 are almost duplicate - they have the same values but in reverse order. How can I delete these duplicates?
+--------+-------+
| COL_1 | COL_# |
+--------+-------+
| a1 | b1 |
| b1 | a1 | <- same as 1stline but in reversed order, needs to be removed
| a2 | b2 |
| a3 | b3 |
| b3 | a3 |<-- also is duplicate of string above, one of these 2str need
+--------+-------+ to be removed
expected result:
+--------+-------+
| COL_1 | COL_# |
+--------+-------+
| b1 | a1 |
| a2 | b2 |
| a3 | b3 |
+--------+-------+
or
+--------+-------+
| COL_1 | COL_# |
+--------+-------+
| a1 | b1 |
| a2 | b2 |
| a3 | b3 |
+--------+-------+
Do you mean like this :
DELETE(
select e.COL_#, f.COL_1
from example as e
join example as f on e.COL_# = f.COL_1 and e.COL_# < f.COL_1 )
If col_1 and col_# cannot be null, you can use LEASTand GREATEST to keep one row per combination:
delete from tbl
where rowid not in
(
select min(rowid) -- one rowid per combination to keep
from tbl
group by least(col_1, col_#), greatest(col_1, col_#)
);
I think it is a bit complicated to achieve it with a delete query.
Maybe it is OK for you to have such a select query first:
select A,B from (
select A,
B,
ROW_NUMBER() over (PARTITION BY ORA_HASH(A) * ORA_HASH(B) ORDER BY A) as RANK
FROM <your_table_name>
) where RANK = 1;
You could save the result of this query as a new table with CREATE TABLE AS SELECT ...
And then you simply DROP your old table.
One possible solution is:
DELETE FROM T
WHERE (COL_1, "COL_#") IN (SELECT COL_1, "COL_#"
FROM (SELECT ROWNUM AS RN, t1.COL_1, t1."COL_#"
FROM T t1
INNER JOIN T t2
ON t2."COL_#" = t1.COL_1 AND
t2.COL_1 = t1."COL_#")
WHERE RN / 2 <> TRUNC(RN / 2));
Note that COL_# must be quoted in Oracle as # is not a legal character in an unquoted identifier.
dbfiddle here
This doesn't seem so complicated:
delete t
where not (col1 < col2 or
not exists (select 1
from t t2
where t2.col1 = t.col2 and
t2.col2 = t.col1
)
);
Or:
delete t
where col1 > col2 and
exists (select 1
from t t2
where t2.col1 = t.col2 and
t2.col2 = t.col1
);

SQL combine rows based on group by in view

I have a table:
c1 c2
----------
A B
A C
X P
X Q
How can i create a view that shows this as
c1 c2 c3
---------------
A B C
X P Q
You can use aggregation:
select c1, min(c2) as c2, max(c2) as c3
from t
group by c1;
You can self join the table:
select
t1.c1, t1.c2, t2.c2 as c3
from tablename t1 inner join tablename t2
on t1.c1 = t2.c1 and t1.c2 < t2.c2
See the demo.
Results:
| c1 | c2 | c3 |
| --- | --- | --- |
| A | B | C |
| X | P | Q |

Join on two tables gives duplicate results

i have a table with data that I want to join unto another table. Problem is that the join can happen on two columns of the same table, where I want to get the first join to work and if this Fails i want the second join to give me a valid result.
Base table:
| ID1 | ID2 | Value |
| a1 | a2 | val_1 |
| b1 | b2 | val_2 |
| c1 | c2 | val_3 |
join Table:
| ID1 | ID2 | Join_Value |
| | a2 | join_val_1 |
| b1 | | join_val_2 |
| c1 | c2 | join_val_3 |
What i tried was this:
select base.id1, base.id2, Value, isnull(j1.Join_value,j2.Join_value) Join_Value from base
left join Join j1 on j1.id1 = base.id1
left join Join j2 on j2.id2 = base.id2
The Result is this:
| ID1 | ID2 | Value | Join_Value |
| a1 | a2 | val_1 | join_val_1 |
| b1 | b2 | val_2 | join_val_2 |
| c1 | c2 | val_3 | join_val_3 |
| c1 | c2 | val_3 | join_val_3 |
What i want is this:
| ID1 | ID2 | Value | Join_Value |
| a1 | a2 | val_1 | join_val_1 |
| b1 | b2 | val_2 | join_val_2 |
| c1 | c2 | val_3 | join_val_3 |
I hope i made my Problem clear.
You don't need to join the same table twice. Just specify the condition in the ON
select b.ID1, b.ID2, b.[Value], j.Join_Value
from [base] b
inner join [join] j on b.ID1 = j.ID1
or (
j.ID1 = ''
and b.ID2 = j.ID2
)
You are going to get duplicate rows for for the c1 and c2 rows because they match on both of your Join table joins (j1 and j2).
A quick fix is to add a DISTINCT to your query:
select DISTINCT base.id1, base.id2, Value, isnull(j1.Join_value,j2.Join_value) Join_Value
from base
left join Join j1 on j1.id1 = base.id1
left join Join j2 on j2.id2 = base.id2
A better fix, depending on your DBMS is to use a window function:
select id1, id2, Value, Join_Value
FROM (
select base.id1, base.id2, Value, isnull(j1.Join_value,j2.Join_value) Join_Value,
ROW_NUMBER() OVER(
PARTITION BY base.id1, base.id2 -- Group rows based on (id1, id2) combination
ORDER BY j1.id1 -- If more than one row, give priority to row with "id1" value
) AS RowNum
from base
left join Join j1 on j1.id1 = base.id1
left join Join j2 on j2.id2 = base.id2
) src
WHERE RowNum = 1 -- Only return one row
This will make sure you always one row maximum per (id1, id2) combination.
Try:
select *
from base b
join [join] j on b.id1 = j.id1 or b.id2 = j.id2
First, your version does exactly what you want. Here is a db<>fiddle.
Second, for more control over the matching, you can use a lateral join. This allows you to choose only one matching row -- say the one where both ids match:
select b.id1, b.id2, b.value, jt.join_value
from base b cross apply
(select top (1) jt.*
from jointable jt
where b.id1 = jt.id1 or
b.id2 = jt.id2
order by (case when b.id1 = jt.id1 then 1 else 0 end) +
(case when b.id2 = jt.id2 then 1 else 0 end) desc
) jt ;

How to get a fixed number of rows in sql

If I have 4 rows in database like these.
|____A____|____B_____|
| a1 | b1 |
| a2 | b2 |
| a3 | b3 |
| a4 | b4 |
But I need to display 10 rows by added NO column to get serial number for each row like these
__NO__|____A____|____B_____|
1 | a1 | b1 |
2 | a2 | b2 |
3 | a3 | b3 |
4 | a4 | b4 |
5 | | |
6 | | |
7 | | |
8 | | |
9 | | |
10 | | |
How to query by sql server?
Fiddle here : http://sqlfiddle.com/#!3/9a9dd/1
WITH CTE1
AS
(
SELECT 1 AS [NO]
UNION ALL
SELECT [NO]+1 FROM CTE1 WHERE [NO]<10
),
CTE2 AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS RN, A,B
FROM YOURTABLE
)
SELECT C1.[NO],A,B
FROM CTE1 C1 LEFT JOIN CTE2 C2 ON C1.[NO] = C2.RN
Here is another way without using recursive cte and LEFT JOIN.
SQL Fiddle
;WITH Cte AS(
SELECT
NO = ROW_NUMBER() OVER (ORDER BY A, B), A, B
FROM tbl
UNION ALL
SELECT
t.n, NULL, NULL
FROM (VALUES
(11), (12), (13), (14), (15), (16), (17), (18), (19), (20)
)t(n)
),
CteFinal AS(
SELECT *, rn = ROW_NUMBER() OVER (ORDER BY NO)
FROM Cte
)
SELECT
rn AS NO, A, B
FROM CteFinal
WHERE rn < = 10

Sql Server get first matching value

I have two tables History and Historyvalues:
History
HID(uniqeidentifier) | Version(int)
a1 | 1
a2 | 2
a3 | 3
a4 | 4
Historyvalues
HVID(uniqeidentifier) | HID(uniqeidentifier) | ControlID(uniqeidentifier) | Value(string)
b1 | a1 | c1 | value1
b2 | a2 | c1 | value2
b3 | a2 | c2 | value3
Now I Need a query where I can get a list with the last historyvalue of each control from a specific Version like:
Get the last values from Version 3 -> receiving ->
HVID | ControlID | Value
b2 | c1 | value2
b3 | c2 | value3
I tried something like this:
Select HVID, ControlId, max(Version), Value from
(
Select HVID, ControlId, Version, Value
from History inner JOIN
Historyvalues ON History.HID = Historyvalues.HID
where Version <= 3
) as a
group by ControlId
order by Version desc
but this does not work.
Are there any ideas?
Thank you very much for your help.
Best regards
Latest version from each control with your specific Version (WHERE t1.Version <= 3)
Query:
SQLFIDDLEExample
SELECT HVID, ControlId, Version, Value
FROM
(
SELECT t2.HVID, t2.ControlId, t1.Version, t2.Value,
ROW_NUMBER() OVER(PARTITION BY t2.ControlId ORDER BY t1.Version DESC) as rnk
FROM History t1
JOIN Historyvalues t2
ON t1.HID = t2.HID
WHERE t1.Version <= 3
) AS a
WHERE a.rnk = 1
ORDER BY a.Version desc
Result:
| HVID | CONTROLID | VERSION | VALUE |
|------|-----------|---------|--------|
| b2 | c1 | 2 | value2 |
| b3 | c2 | 2 | value3 |
here is your solution
Select Historyvalues.HVID,Historyvalues.ControlID,Historyvalues.Value
from Historyvalues
inner join History on Historyvalues.hid=History.hid
where Historyvalues.hvid in (
select MAX(Historyvalues.hvid) from Historyvalues
inner join History on Historyvalues.hid=History.hid
group by ControlID)