Join table with different primary key values - sql

I want to join two tables with different primary key values as below
Table A
id name
1 John
2 Smith
and Table B
id name
1-x Foo
2-x Bar
I've tried using LIKE statements on my query but it won't stop executing.
SELECT * FROM A a JOIN B b ON a.id LIKE b.id +'%'
Is there any efficient way to JOIN these two tables?

If you use a query like this:
SELECT *
FROM A a JOIN
B b
ON a.id || '-x' = b.id;
Then SQLite should be able to use an index on B(id) for the query. It is worth a try.

No, there's no efficient way of joining them.
That doesn't mean it cannot be done (it can), but it probably doesn't make sense.
Primary keys are not supposed to be good looking or sexy. They are unique row identifiers. If you have a primary key with a value like that, it's because you probably want to expose it or display it somewhere; and that's not their goal.
If you need a nice looking row identifier I suggest you create a secondary unique column that could even be auto-generated.
Bottom line, keep the primary key simple.

Related

How can I use multiple primary keys to join tables using string_split?

I have two or even three primary keys stored in column called "PrimaryKeys". I have to use these keys in a join condition dynamically.
I have tried this and I think I have to use string_split to first split the primary keys from the column and then concatenate them in the join condition. But I am not sure how.
for example, if i have (Id, Person_name, Address) in the column,
I want the sql query to work like:
---do stuff
join on a. Id= b. Id, a.Person_name=b.Person_name, a.Address=b.Address)
Can Someone help?
wouldn't simply
join on a. Id= b. Id **and** a.Person_name=b.Person_name **and** a.Address=b.Address
work?

Can we join two parts of two composite primary keys together?

I have to two tables, both have a composite primary key:
OrderNr + CustNr
OrderNr + ItemNr
Can I join both tables with the OrderNr and OrderNr which is each a part of a composite primary key?
Yes, but you may find you get rows from each table that repeat as they combine to make a unique combination. This is called a Cartesian product
Table A
OrderNr, CustNr
1,C1
1,C2
2,C1
2,C2
TableB
OrderNr,ItemNr
1,i1
1,i2
SELECT * FROM a JOIN b ON a.OrderNr = b.OrderNr
1,C1,1,i1
1,C1,1,i2
1,C2,1,i1
1,C2,1,i2
This happens because composite primary keys can contain repeated elements so long as the combination of elements is unique. Joining on only one part of the PK, and that part being an element that is repeated (my custnr 1 repeats twice in each table, even though the itemnr and CustNr mean the rows are unique) results in a multiplied resultset - 2 rows from A that are custnr 1, multiplied by 2 rows from B that are custnr 1, gives 4 rows in total
Does it work with the normal/naturla join too?
Normal joins (INNER, LEFT OUTER, RIGHT OUTER, FULL OUTER) will join the rows from two tables or subqueries when the ON condition is valid. The clause in the ON is like a WHERE clause, yes - in that it represents a statement that is true or false (a predicate). If the statement is true, the rows are joined. You don't even have to make it about data from the tables - you can even say a JOIN b ON 1=1 and every rows from A will get joined to every row from B. As commented, primary keys aren't involved in JOINS at all, though primary keys often rely on indexes and those indexes may be used to speed up a join, but they aren't vital to it.
Other joins (CROSS, NATURAL..) exist; a CROSS join is like the 1=1 example above, you don't specify an ON, every row from A is joined to every row from B, by design. NATURAL JOIN is one to avoid using, IMHO - the database will look for column names that are the same in both tables and join on them. The problem is that things can stop working in future if someone adds a column with the same name but different content/meaning to the two tables. No serious production system I've ever come across has used NATURAL join. You can get away with some typing if your columns to join on are named the same, with USING - SELECT * FROM a JOIN b USING (col) - here both A and B have a column called col. USING has some advantages, especially over NATURAL join, in that it doesn't fall apart if another column of the same name as an existing one but it has some detractors too - you can't say USING(col) AND .... Most people just stick to writing ON, and forget USING
NATURAL join also does NOT use primary keys. There is no join style (that I know of) that will look at a foreign key relationship between two tables and use that as the join condition
And then is it true that if I try to join Primary key and foreign key of two tables, that it works like a "where" command?
Hard to understand what you mean by this, but if you mean that A JOIN B ON A.primarykey = B.primary_key_in_a then it'll work out, sure. If you mean A CROSS JOIN B WHERE A.primarykey = B.primary_key_in_a then that will also work, but it's something I'd definitely avoid - no one writes SQLs this way, and the general favoring is to drop use of WHERE to create joining conditions (you do still see people writing the old school way of FROM a,b WHERE a.col=b.col but it's also heavily discouraged), and put them in the ON instead
So, in summary:
SELECT * FROM a JOIN b ON a.col1 = b.col2
Joins all rows from a with all rows from b, where the values in col1 equal the values in col2. No primary keys are needed for any of this to work out
You can join any table if there is/are logical relationship between them
select *
from t1
JOIN t2
on t1.ORderNr = t2.OrderNr
Although if OrderNr cannot provide unicity between tables by itself, your data will be multiplied.
Lets say that you have 2 OrderNr with value 1 on t1 and 5 OrderNr with value 1 on t2, when you join them, you will get 2 x 5 = 10 records.
Your data model is similar to a problem commonly referred to as a "fan trap". (If you had an "order" table keyed solely by OrderNr if would exactly be a fan trap).
Either way, it's the same problem -- the relationship between Order/Customers and Order/Items is ambiguous. You cannot tell which customers ordered which items.
It is technically possible to join these tables -- you can join on any columns regardless of whether they are key columns or not. The problem is that your results will probably not make sense, unless you have more conditions and other tables that you are not telling us about.
For example, a simple join just on t1.OrderNr = t2.OrderNr will return rows indicating every customer related to the order has ordered every item related to the order. If that is what you want, you have no problem here.

View new count column

I have 2 tables. One who is like a transactional table
userId category
Second table also has
userId (as primary key)
and other columns (not important)
I wanted to create a view based on these 2 tables. Also, I want to have one column which puts into the cells the count from the transactional table who has the same id and eventually matches a special categorie f.e "car".
I thought of maybe using nested select statement, but since i'm a beginner i'm a little bit confused.
Try something like this.
select count(b.userId) as ID, b.category from table2 a inner join transactional b
on a.userId = b.userId where b.category= 'car' group by b.category;

Access: Updatable join query with 2 primary key fields that are both also foreign keys

In MS Access, I am trying to implement a many-to-many table that will store 2-way relationships, similar to Association between two entries in SQL table. This table stores info such as "Person A and Person B are coworkers" "C and D are friends", etc. The table is like this:
ConstitRelationships
LeftId (number, primary key, foreign key to Constituents.ConstitId)
RightId (number, primary key, foreign key to Constituents.ConstitId)
Description (text)
Note that the primary key is a composite of the two Id fields.
Also the table has constraints:
[LeftId]<>[RightId] AND [LeftId]<[RightId]
The table is working ok in my Access project, except that I cannot figure out how to make an updateable query that I want to use as a datasheet subform so users can easily add/delete records and change the descriptions. I currently have a non-updatable query:
SELECT Constituents.ConstituentId, Constituents.FirstName,
Constituents.MiddleName, Constituents.LastName,
ConstitRelationships.Description, ConstitRelationships.LeftId,
ConstitRelationships.RightId
FROM ConstitRelationships INNER JOIN Constituents ON
(Constituents.ConstituentId =
ConstitRelationships.RightId) OR (Constituents.ConstituentId =
ConstitRelationships.LeftId);
If I ignore the possibility that the constituentId I want is in the leftId column, I can do this, which is updatable. So the OR condition in the inner join above is what's messing it up.
SELECT Constituents.ConstituentId, Constituents.FirstName,
Constituents.MiddleName, Constituents.LastName,
ConstitRelationships.Description, ConstitRelationships.LeftId,
ConstitRelationships.RightId
FROM ConstitRelationships INNER JOIN Constituents ON
(Constituents.ConstituentId =
ConstitRelationships.RightId) ;
I also tried this wacky iif thing to collapse the two LeftId and RightId fields into FriendId, but it was not updateable either.
SELECT Constituents.ConstituentId, Constituents.FirstName,
Constituents.MiddleName,
Constituents.LastName, subQ.Description
FROM Constituents
INNER JOIN (
SELECT Description, Iif([Forms]![Constituents Form]![ConstituentId] <>
ConstitRelationships.LeftId, ConstitRelationships.LeftId,
ConstitRelationships.RightId) AS FriendId
FROM ConstitRelationships
WHERE ([Forms]![Constituents Form]![ConstituentId] =
ConstitRelationships.RightId)
OR ([Forms]![Constituents Form]![ConstituentId] =
ConstitRelationships.LeftId)
) subQ
ON (subQ.FriendId = Constituents.ConstituentId)
;
How can I make an updatable query on ConstitRelationships, including a JOIN with the Constituent.FirstName MiddleName LastName fields?
I am afraid that is not possible. Because you use joins in your query over three tables it is not updatable. There is no way around this.
Here some detailed information about the topic: http://www.fmsinc.com/Microsoftaccess/query/non-updateable/index.html
As mentioned in the linked article one possible solution and in my opinion best solution for you would be the temporary table. It is a load of work compared to the easy "bind-form-to-a-query"-approach but it works best.
The alternative would be to alter your datascheme in that way that you do not need joins. But then denormalized data and duplicates would go rampage which makes the temporary table a favorable choice.

How do I (quickly) collate IDs from various tables?

I have three denormalized tables that I have to take at face value (data comes from some external resource). The three tables have different definitions, but they each describe the same object from different perspectives.
object1 A B
object2 A
object3 B C
object4 C
The only commonality between these tables is their primary key. I can corral the IDs together using SELECT UNION SELECT, but the query seems relatively slow, even when each table has its PK field indexed. I could create a view to abstract this query, vw_object_ids, but it performs at the same speed. I thought I could add an index to materialize the view, but in SQL Server 2005, you can't index views with UNIONs.
What I want is to have a master index of IDs be in sync with with the underlying data, which may get updated or deleted whenever. I guess I could accomplish this indefinitely with a crazy set of triggers or just settle for the speed of the unindexed view. But I just wanted to make sure I'm not missing any options or if this scenario has a name or is indicative of a pattern.
Thoughts?
Create a master table that contains only the ID:
CREATE TABLE master (ID INT NOT NULL PRIMARY KEY)
and make all three tables to refer to that master table with ON DELETE CASCADE.
To populate the table for the first time, issue
INSERT
INTO master
SELECT id
FROM a
UNION
SELECT id
FROM b
UNION
SELECT id
FROM c
To populate the table on a regular basis, create a trigger on each of three tables.
This trigger should try to insert the new ID to master and silently fail on PRIMARY KEY violation.
To query, use:
SELECT *
FROM master m
LEFT OUTER JOIN
a
ON a.id = m.id
LEFT OUTER JOIN
b
ON b.id = m.id
LEFT OUTER JOIN
c
ON c.id = m.id
This will use indexes efficienty.
To delete, use:
DELETE
FROM master
WHERE id = #id
This will fire ON DELETE CASCADE and delete records from all three tables if any.
Why not just do an outer join and then coalesce the columns from the component tables?