SQL Server - How to determine shared key between 2 tables? - sql-server

For example, if I want to link OPOR, ORDR & ODLN but do not know what the common key between them is, how can I find this out?
Example:
SELECT o0.NumAtCard 'Customer PO'
, o0.DocNum 'Sales Order No'
, o1.DocNum 'Purchase Order No'
, o2.DocNum 'Delivery Order No'
, o0.DocTotal 'Total Price'
FROM ORDR o0
JOIN OPOR o1 ON o0.primarykey = o1.foreignkey -- left?
JOIN ODLN o2 ON o1.primarykey = o2.foreignkey -- inner?
How do I determine what the "primarykey" and "foreignkey" is?
OPOR's table structure:
ODLN table structure:

If you scroll down your sp_help results, you should see constraint. If there is a primary key constraint, look at what key it uses. The primary key is usually the one used to linked to another table.

You need to know the structure of the two tables. In SQL server:
sp_help TableA;
sp_help TableB;
In MySQL:
describe TableA;
describe TableB;
This will show you the table structure. If the database is designed well, you should be able to tell which columns are the foreign keys.
As far as knowing which columns to join on based on the results you posted:
1) You might be expecting something that isn't there.
2) It can depend on what you want to do. Suppose you want to match rows in OPOR to ODLN where they are marked as cancelled in ODLN, you would go:
select * from OPOR
inner join ODLN on
OPOR.DocEntry=ODLN.DocEntry
where CANCELLED='true';
or whatever a valid value for cancelled is. But without knowing your desired query or understanding more about the meaning of these columns, I can't really advise. The tables appear to be exactly the same which suggests it would be unusual to join them.

Related

Microsoft SQL -- struggles with CROSS JOIN

So i have to do a cartesian product (or CROSS JOIN) between two tables. One problem is that both tables have a column with the name 'itemname'. My current case looks as follows:
select *
into #cartesian_temp
from xsale CROSS JOIN xitem
delete from #cartesian_temp where deptname='books' and itemcolor='bamboo'
select * from #cartesian_temp
so the error I get is:
Column names in each table must be unique. Column name 'itemname' in table '#cartesian_temp' is specified more than once
Anyone that can help me with my problem?
you can add alias for the columns like below.
select XS.itemname as saleitemname , XI.itemname as saleitemname2
into #cartesian_temp
from xsale XS CROSS JOIN xitem XI
This is one of the reasons why seasoned SQL pro's will ALWAYS advocate to give Tables an alias and to ALWAYS fully qualify every column name by using the alias. It's not just a cross join problem
Avoid this:
SELECT *
FROM
person
INNER JOIN
address
ON addressid = address.id -- Person.addressid
Sure, it'll work as long as the column names are all unique (it'll probably cause issues even now because person will have an I'd column and so will address) but it might stop working at any point in future if someone adds columns to either table with names that clash
Prefer this:
SELECT p.id as personid, a.id as addressid, p.name, a.zipcode
FROM
person p
INNER JOIN
address a
ON p.addressid = a.id
This is fully aliased (both tables have an alias) and we haven't used select *; weve fully qualified every column with a prefix using the table alias and we've aliased columns that have the same named (the ID columns) in each table so we can tel them apart. No one can add any columns to the db and cause this query to stop working
Aliasing Tables helps in another way; it lets us use the same table twice in a query. Suppose a person had a work address and a home address:
SELECT ...
FROM
person p
INNER JOIN
address awork
ON p.workaddressid = awork.id
INNER JOIN
address ahome
ON p.homeaddressid = ahome.id
This is impossible without aliasing. Always give aliases a sensible name (not a1, a2)
For your case, go like:
SELECT xs.itemname as xsitemname, xi.itemname as xiitemname, ...
FROM
xsale xs
CROSS JOIN
xitem xi
WHERE
xi.itemcolor = 'green'
This will be every green item crossed with every sale item

Alternatives to FULL OUTER JOIN

We have a query that looks for discrepancies between two tables in two different databases (one SQL Server, one Oracle) that in theory should always be in sync. The query pulls the data from both tables into table variables and then does a FULL OUTER JOIN to find the discrepancies. We suspect that the FULL OUT JOIN is partially to blame for the performance issues.
Would it make sense to rely on two LEFT OUTER JOINs and look for records that don't exist on the right side of the join?
We're also thinking about using temp tables to further help with performance.
One option is to do a inner join and store results in a temp table. Then do a select from TableA where not exists in tempTableWithCommonRecords
and another select from TableB where not exists in tempTableWithCommonRecords
Cant say if this will perform better as don't have enough info for that. Its just another option.
You can try the EXCEPT operator which handles complex joins, and it should work in both PL-SQL and T-SQL. It will return any values in the left table that are not a perfect match on the right table:
SELECT [Field1], [Field2], [Field3]
FROM Table1
EXCEPT
SELECT [Field1], [Field2], [Field3]
FROM Table2
UNION
SELECT [Field1], [Field2], [Field3]
FROM Table2
EXCEPT
SELECT [Field1], [Field2], [Field3]
FROM Table1

SQL: Building hierarchies and nesting queries on the same table

I am trying to build hierarchies by nesting queries on the same table in MS SQL Server 2014.
To give an example of what I am trying to achieve:
I have a table 'employees' whith the following columns:
[ID],[First Name],[Last Name],[ReportsTo]
{1},{John},{Doe},{2}
{2},{Mary},{Miller},{NULL}
I am trying to build a statement, where I join the employees table with itself and where I build a hierarchy with the boss on top.
Expected Result:
[Employee],[Boss]
{Miller,Mary},{NULL}
{Doe, John},{Miller,Mary}
I apologize, if this is a stupid question, but I fail to create a working nested query.
Could you please help me with that?
Thank you very much in advance
Based on the intended results, it looks like what you essentially want is a list of employees. So let's start with that:
SELECT LastName, FirstName, ReportsTo FROM Employees
This gives you the list, so you now have the objects you're looking for. But you need to fill out more data. You want to follow ReportsTo and show data from the record to which that points as well. This would be done exactly as it would if the foreign key pointed to a different table. (The only difference from being the same table is that you must use table aliases in the query, since you're including the same table twice.)
So let's start by joining the table:
SELECT e.LastName, e.FirstName, e.ReportsTo
FROM Employees e
LEFT OUTER JOIN Employees b on e.ReportsTo = b.ID
The results should still be the same, but now you have more data to select from. So you can add the new columns to the SELECT clause:
SELECT
e.LastName AS EmployeeLastName,
e.FirstName AS EmployeeFirstName,
b.LastName AS BossLastName,
b.FirstName AS BossFirstName
FROM Employees e
LEFT OUTER JOIN Employees b on e.ReportsTo = b.ID
It's a join like any other, it just happens to be a join to the same table.

SQL View Optimization

I am trying to build a view that does basically 2 things, whether a record in table 1 is in table 2 and whether a link to another table is still there. it worked on a subset of data, but when i tried to run the full query it timed out in the view designer.
The view worked fine until I added in the check to see whether the link to another table was present.
Initially it joined table A to Table B and filtered out where A.ID wasnt present in the ID column in table B
I was then told that if the link between the person and the address table (stored in table C) was removed then we would have no way of knowing other than to get a full extract of that table again and see which links are no longer present. I am trying to use that check to determine whether to display some data in particular columns
I am using the following structure close to 60 times to choose whether to show information in a column:
Column1 = case when exists (select LinkID from LinkTable C
where cast(C.LinkAddressID as varchar) = A.AddressID
and cast(C.LinkID as varchar) = A.ID)
then Column1
else NULL
end
There is about 1.6m records in Table A just over 4m records in the Link table.
is there a better way to write this query / view that would be more optimized?
Please let me know if more information is needed
Select C.LinkID
From A
Left Join C On C.LinkAddressID = A.AddressID And C.LinkID = A.ID
This will give you C.LinkID if a match exists on the two conditions and NULL if both criteria are not satisfied.
Having indexes / keys such as primary key on A.ID and foreign key relationships based on what is in the join clause will provide very good performance.
As Joe suggested, if for all 60 columns you use the same AddressId and Id fields to match two tables, I believe so you can use something as following query
SELECT
Column1 = CASE WHEN C.LinkID IS NULL THEN NULL ELSE A.Column1 END,
....
FROM A
Left Join LinkTable C
ON C.LinkAddressID = A.AddressID AND C.LinkID = A.ID
Casting data types will definitely disable the advantage from index. So keep away data type cast if possible on joins and in WHERE clauses

Searching for the unique key (not in meta)

With which SQL Server standard tool it is possible to search unique key in the table's data (but not in meta declaration)?
P.S. I am thinking to write such script by myself. May be you could point a snippet for
combinatorics in t-sql? e.g. for generation all Combinations from n by 1..n ?
P.P.S About problem complexity for those who do not see it. It is important that we do not need to analyze the whole data to dismiss the hypnotize that those two columns is the 'unique key'. With real world, 'report-like', sorted data even after analysing first two rows, I think, it is possible to remove many of columns combinations. So I feel such algorithm should have 'before full table compare' phase. But there it is a question for what portion of data to choose for this 'before full table compare' phase . The best candidate about which I think is the 'page'... If data unique in the page we could test the uniqueness on whole table, if not unique (on the page), then go to the next column set.
select t1.col, count(*)
from table t1
join table t2
on t1.col = t2.col
group by t1.col
having count(*) > 1
if zero rows are returned then it is unique
more than one column
select t1.cola, t1.colb, count(*)
from table t1
join table t2
on t1.cola = t2.cola
and t1.colb = t2.colb
group by t1.cola, t2.colb
having count(*) > 1

Resources