SQL calculate difference between cell values - sql

Hi i was wondering if anyone knows how i can calculate the difference between two tables in tsql. I dont mean finding which cells are different - i mean calulcating the numerical difference. eg - Table A has column1, column 2 and only one 1 row. A1 = 40, B1 = 30. Table B has column1, column 2 and only one 1 row. A1 = 25, B1 = 10. So how could i get (A1 = 15, B1 = 20) using TSQL?

Given that you have no way to join the tables, you'll need a Cartesian product of the two. Luckily since each table only has one record that's not a problem.
You do it like this:
SELECT
TableA.A1 - TableB.A1 AS A1,
TableA.B1 - TableB.B1 AS B1
FROM TableA, TableB
If you had more than one record in each table, this query would return a result for every pair of records in both tables. So if TableA had n records and TableB has m, the result will have n*m records.

SELECT a.column1 - b.column1 , a.column2 - b.column2
FROM a
CROSS JOIN
b

Free from my mind =)
Select
(CONVERT(int, T1.A1) - Convert(int, T2.A1)) as A1,
(CONVERT(int, T1.B1) - Convert(int, T2.B)) as B1
From Table1 T1
inner join Table2 T2 on T1.Key = T2.Key

Related

How do I SELECT only rows from table b that have all the same values for a given column per foreign key?

I have a table that just has ID's.
Another table that has ID plus a couple other columns.
One such column is [set], for reference.
I am trying to build a join query on only the ID's in table2 that have the same value for every row in column [set], not just ID'S that have a duplicate value in [set] plus another different value. So, each ID in table2 can have multiple rows.
table1
[id]
a1
a2
table2
[id]
[op]
[set]
a1
22
cut
a1
21
cut
a2
23
cut
a2
25
cut
a2
24
slice
In the given example, 'a2' would not fit the criteria because the values in column [set] are not all the same.
My query isn't working.
SELECT DISTINCT(A.ID)
FROM TABLE1 A
INNER JOIN TABLE2 B ON A.ID = B.ID
GROUP BY A.ID, B.SET
HAVING COUNT(DISTINCT(B.SET)) =1
You're grouping by id and set, so by definition within each group, there will be just one value for set. Remove it from the group by clause and you should be OK. Also, not that since you're grouping by the id, you don't need a distinct on it:
SELECT A.ID -- Distinct removed. It's not wrong, just redundant
FROM TABLE1 A
INNER JOIN TABLE2 B ON A.ID = B.ID
GROUP BY A.ID -- Grouping by b.set removed
HAVING COUNT(DISTINCT(B.SET)) = 1

Fetching fields with specific criteria - Oracle

I am trying to extract particular data from 2 tables based on specific criteria. But the result is not as expected. Can someone please help?
Criteria:
Need to fetch id pairs whose type is A alone.
Tables:
Table A
ID1 ID2
579643307310619501 644543316683180704
296151129721950503 328945291791563504
Table B
ID TYPE
579643307310619501 A
579643307310619501 B
579643307310619501 C
644543316683180704 A
296151129721950503 A
328945291791563504 A
Expected Result:
ID1 ID2
296151129721950503 328945291791563504
(Since only this pair is of type A alone, individually)
Note: The IDs, ID1 and ID2 both must be present in ID field of Table B.
What I've tried:
SELECT id1, id2
FROM A
JOIN B ON A.id1 = B.id
WHERE A.id1 IN (SELECT id FROM B)
AND A.id2 IN (SELECT id FROM B)
AND B.type='A'
GROUP BY id1, id2
HAVING count(*)=1;
In the approach below, I use a CTE to first identify all ID values having exclusively the 'A' type. Then I join TableA to this CTE, twice, to filter off any records either of whose ID1 or ID2 values are not in the exclusively 'A' type list.
WITH cte (ID) AS (
SELECT ID
FROM TableB
GROUP BY ID
HAVING SUM(CASE WHEN TYPE <> 'A' THEN 1 ELSE 0 END) = 0
)
SELECT a.ID1, a.ID2
FROM TableA a
INNER JOIN cte t1
ON a.ID1 = t1.ID
INNER JOIN cte t2
ON a.ID2 = t2.ID;
Find below a working demo (for SQL Server - I can't get Oracle to work anywhere).
Demo
Here is an Oracle solution using the MINUS operator.
The top sub-query gets the set of records where both ID1 and ID2 are of type 'A'. The bottom sub-query gets the set of records where either ID1 or ID2 is not of type 'A'. The result is the set of records in the top set which are not also in the bottom set.
select a.id1, a.id2
from a
join b b1 on b1.id = a.id1
join b b2 on b2.id = a.id2
where b1.type = 'A'
and b2.type = 'A'
minus
select a.id1, a.id2
from a
join b b1 on b1.id = a.id1
join b b2 on b2.id = a.id2
where b1.type != 'A'
or b2.type != 'A'
/
This SQL Fiddle demo returns the right row but there's a bit of a problem with its display: for some reason the numbers are rounded down.
Note on performance
This hits table A twice and table B four times. With small tables and a well-sized buffer cache this is not so important.
#TimBiegeleisen uses the WITH clause and that approach only hits each table once. However, Oracle will materialize the CTE as a temporary table. The overhead of doing this for such small amounts of data makes his solution consistently slower than mine. Including an /*+ inline */ hint in the CTE projection prevents Oracle from materializing the temporary table and the performance of the two queries becomes comparable.
However, if the tables become large enough there will be a point at which the WITH clause approach with a materialized temporary table is the more performative approach. As always with query tuning, the specifics matter greatly and benchmarking is the key to success.
Here is a sample for Oracle and my solution.
This is valid for any letter, A, B, C... If you want only for A, add an additional filter in the where of the main query.
create table a (id1 number,id2 number, constraint pk_a primary key(id1,id2));
create table b (id number, type char(1), constraint pk_b primary key(id,type));
insert into a values(57,64);
insert into a values(29,32);
insert into b values(57,'A');
insert into b values(57,'B');
insert into b values(57,'C');
insert into b values(64,'A');
insert into b values(29,'A');
insert into b values(32,'A');
commit;
select a.*
from a, b b1, b b2
where a.id1 = b1.id
and a.id2 = b2.id
and b1.type = b2.type
and not exists (select null
from b b1bis
where b1bis.id = b1.id
and b1.type <> b1bis.type)
and not exists (select null
from b b2bis
where b2bis.id = b2.id
and b2.type <> b2bis.type);

Is there a way to do a multi table query and get result just from specific tables?

I am trying to do a multi query but I don't want to use sub queries i.e:
SELECT column1
FROM table1
WHERE
EXISTS (SELECT column1 FROM table2 WHERE table1.column1 = table2.column1);)
I thought of using a JOIN but so far my best result was this:
SELECT *
FROM table1
JOIN table2 ON table1.t1id = table2.t2id
WHERE table1.id = 5;
This would be good except of the fact that I get a duplicate column (the id in table 1 and 2 are foreign keys).
How do I remove the duplicate column if possible?
UPDATE:
Table1:
tableA_ID, TABLEB_ID
1, 1
1, 4
3, 2
4, 3
TableA: ID, COL1, COL2
1, A, B
2, A, B
3, A, B
4, A, B
TableB: ID, Col3, COL4
1, C, D
2, C, D
3, C, D
4, C, D
I want to get all or some of the columns from TableA according to a condition
Sample: Lets say the condition is that tableA_ID = 1 which will result in the 2 first rows in the table then I want to get all or some of the columns in TableA that respond to the ID that I got from Table1.
Sample: The result from before was [{1,1}{1,4}] which means I want from TableA the results:
TableA.ID, TableA.COL1, TableA.COL2
1,A,B
4,A,B
The actual results I get is:
Table1.tableA_ID, Table1.TABLEB_ID, TableA.ID, TableA.COL1, TableA.COL2
1,1,1,A,B
1,4,4,A,B
Is this what you're looking for?
select a.id, a.column1, b.column2
from table1 a
left join table2 b on a.id = b.otherid;
You can't change the column list of a query based on the values it returns. It just isn't the way that SQL is designed to operate. At best, you can return all of the columns from the second table and ignore the ones that aren't relevant based on other values in that row.
I'm not even sure how a variable column list would work. In your scenario, you're looking for two discrete values separately. But that's not the only scenario: what if the condition is tableA_ID in (1,2). Would you want different numbers of columns in different rows as part of a single result set?
Getting just the columns you want (just from specific tables, as you say) is the easy part (btw -- don't use '*' if you can help it -- topic for another discussion):
SELECT
A.ID,
A.COL1,
A.COL2
FROM
TABLE1 Bridge
LEFT JOIN TABLEA A
ON Bridge.TABLEA_ID = A.ID
LEFT JOIN TABLEB B
ON Bridge.TABLEB_ID = B.ID
Getting the rows you want will be the harder part (influenced by your choice of joins, among several other things).
I think you'll need to select only the fields of table A and use a distinct clause. Rest of your query will remain as it is. i.e.
SELECT distinct table1.*
FROM table1
JOIN table2 ON table1.t1id = table2.t2id
WHERE table1.id = 5;

SQL Multiple Tables

I have 2 sets of 2 corresponding tables (4 tables total). The two sets only correspond in one column. I want the query to search through that one column in both joined tables, and be able to return the value in the selected column, even if that column doesn't exist in the other table.
Currently, my query looks like:
select z
FROM A1
INNER JOIN A2
ON A1.x=A2.x
WHERE A1.x= '25'
UNION
select z
FROM B1
INNER JOIN B2
ON B1.x=B2.x
WHERE B1.x= '25'
UNION works as long as I am looking for a column which both (joined) tables A and B have in common. I'd like to be able to get values from columns which only exist in A or in B, but not necessarily both of them.
Thanks in advance.
Edit:
Basically, I want two completely separate queries on separate tables, but in one query, with only one select.
Example:
Table A1
x | y
------
1 | a
2 | b
Table A2
x | z
------
1 | c
2 | d
Table B1
x | v
------
3 | e
4 | f
Table B2
x | w
------
3 | g
4 | h
So I want look for a column variable (such as v,w,y, or z), with a specified value of x. e.g. select w where x=4 should give me h; select z where x=2 should give me d.
You must have the same number of columns in each select statement when using UNION. You can add constant values for columns that are missing. You must also have the same data type for each column.
select Column1, null as Column2
from T1
union
select '', Column2
from T2
As per comment by #Adrian, you can of course use null as a constant value. Otherwise you need to pick a constant value of the data type that is used for the column.
select Column1, null as Column2
from T1
union
select null, Column2
from T2
Use the sample data provided in the question:
select A1.x, A2.z as 'y'
from A1
inner join A2
on A1.x=A2.x
where A1.x= 4
union
select B1.x, B2.w as 'y'
from B1
inner join B2
on B1.x=B2.x
where B1.x= 4
Result:
x y
4 h
With a 2 instead of a 4
Result:
x y
2 d
It would be something like that:
select Column1, ColumnThatOnlyExistsInContextA, null as ColumnThatOnlyExistsInContextB
FROM A1
INNER JOIN A2
ON A1.ID=A2.ID
WHERE A1.ID= '25'
UNION
select Column1, null, ColumnThatOnlyExistsInContextB
FROM B1
INNER JOIN B2
ON B1.ID=B2.ID
WHERE B1.ID= '25'
When using UNION, make sure all queries return result sets that have the same number of columns with the same type. If you want to return a column from the second query in a union that the first query doesn't have, you can modify your first query to have a NULL value for that column.
So you basically want to do:
select Column1
FROM A1
INNER JOIN A2
ON A1.ID=A2.ID
WHERE A1.ID= '25'
UNION
select Column2
FROM B1
INNER JOIN B2
ON B1.ID=B2.ID
WHERE B1.ID= '25'
right?
If so, your problem is probably just that Column1 and Column2 are different types. So, do something like
select cast(Column1 as varchar(255))
and
select cast(Column2 as varchar(255))
Should work!
Well, UNION's only requirement is that the number and type of the fields in each result set being UNIONed must match. So, if B has a Column2 and A doesn't, you can select Column1 from the joined As and Column2 from the joined Bs, and provided A.Column1 and B.Column2 are the same type (you can CAST or CONVERT if necessary) the statement will still work. Maybe I'm not understanding the problem, but I think it's pretty easy to solve.

Compare Every Record from Two Tables

Assuming I have two SQL tables consisting of a single column,
i.e.
Table 1 Table 2
a1 a2
b1 b2
c1 c2
Is there a succinct SQL command to compare each record in one table against each record in the other? (and return true if any record from table 1 matches any record from table 2)
i.e.
if( a1 = a2 OR a1 = b2 OR a1 = c2 OR b1 = a2 OR b1 = b2...)
I want
If any record from table a matches table b (i.e., in a table of ints, they are the same int), return true.
Why not simply
if exists (select 1 from T1 inner join TB on T1.Col = T2.Col)
A full join is well suited to finding differences. To find rows that are missing in either table:
select *
from t1
full join
t2
on t1.col1 = t2.col1
where t1.col1 is null
or t2.col1 is null
This assumes that the single column is unique (i.e. has no duplicate values.)