SQL Table Relations - sql

We have lots of tables in MS SQL that created without table relations many years ago. Now we are trying to create a relationship between these tables. The problem is in many of these developers used fake ids in the tables.
For example:
TABLE A, ID(primary key) -> TABLE B, AID needs to be relational. But developers used some fake ids like -1,-2 to solve some problems in their side. And now when I try to create a relation between TABLE A, ID(primary key) -> TABLE B, AID, I am getting errors.
TABLE A
ID | NAME
1 | name01
2 | name02
TABLE B
ID | NAME | AID
1 | name01 | 1
2 | name02 | -1
3 | name03 | -2
Is there way to solve this problem and is it meaning full what developers did, they didn't use any relations in sql, they are controlling everything in code-behind.
Thanks

You need to add those to your reference table. Something like this:
insert into a (id, name)
select distinct aid, 'Automatically Generated'
from b
where not exists (select 1 from a where b.aid = a.id) and
a.id is not null;
Then you can add the foreign key relationship:
alter table b add constraint fk_b_aid foreign key (aid) references a(id);

The general idea of referential integrity is exactly that you can't have invalid references.
So the best course of action here would be to suck it up and manually clean it up. Create the missing entries in the other table, or delete the records.

You can also ignore checks on existing data. If you are using sql server management studio to create relations there is option to do that just like in this screen shot
Hope it helps

Related

How to Insert from one table to another table from difference Database

Here is my table
Table Suppliers in Database A
ID(AUTONUMBER) | SupplierCode(Unique) | SupplierName
001 supp001 TestA
002 supp002 TestB
003 supp003 TestC
Table Suppliers in Database B
ID(AUTONUMBER) | SupplierCode(Unique) | SupplierName
001 supp001 TestA
003 supp003 TestC
In this case, i want to insert supp002 to table Suppliers in Database B
And it will skip supp001 and supp003 because the SUPPLIERCODE exists
Can anyone help me with this condition
note: SQL Server query not MySQL
Might as well make it an answer
insert into databaseB..suppliers
Select * from databaseA..suppliers where id not in (select id from databaseB..suppliers)
The table references should be correct, but I can't verify. You might want to go databasea.dbo.suppliers if that's the correct full name
Assuming the two databases are on the same server and both tables are part of the "dbo" schema, inserting only those records in the A table that don't already exist in B into the B table can be handled like this:
INSERT INTO DatabaseB.dbo.Suppliers
SELECT ID,SupplierCode, SupplierName FROM DatabaseA.dbo.Suppliers
WHERE SupplierCode NOT IN
(SELECT SupplierCode FROM DatabaseB.dbo.Suppliers)
If the tables in A and B belong to a different schema, replace the "dbo" above with the appropriate schema name(s).
If the databases reside on different servers, this article that discusses creating linked servers may be useful but the syntax will be similar.
Create Linked Servers
I do not normally recommend using In or Not in statements i usually uses joins so try this
Insert into DatabaseB
(SupplierCode,
SupplierName)
Select SupplierCode,
SupplierName
From DatabaseA A
Left join DatabaseB B
On A.SupplierCode = B.SupplierCode
Where B.SupplierCode IS NULL

Join Table vs Foreign Key/Ref

Imagine I have two tables and they have a 1-to-Many relationship. Is it better to have a Join table storing the relationship, or issuing a foreign key in one of these tables? Take a look of these two situations:
Situation A:
Table 1: CreditCard
Table 2: Person
It seems to me quite making sense to put the creditCard_id as part of the Person table
Situation B:
Table 1: Order
Table 2: Person
This time I think I will put the order_id and person_id in a Join table?
Am I making a mistake in the above? Is there a standard/better way of determining this?
For 1 to Many relation, people usually put the foreign key into the heavier table or the "Many" table.
So from your example, both go CreditCard and Order tables, by doing so you will remove duplicate data.
Imagine you which one is better:
FK goes to the "Many" table
Table People:
ID NAME
1 A
2 B
Table CreditCard:
ID PEOPLE_ID
1 1
2 1
FK goes to "1" table:
Table People:
ID NAME CreditCard_ID
1 A 1
1 A 2
2 B 3
Table CreditCard:
ID
1
2
3
Note: See how the ID and Name are repeated(ID=1, NAME=A) in the second example, that happens if you put the FK in the wrong table.
I would make three tables; a person table with all their info( name, address, etc. ), a credit card table with all the info( expiration date, security number?, etc.. ) then another table connecting them with the PersonID and CreditCardID. But what do I know, I'm still in school lol so wait for someone else to answer you.

Recursively duplicating entries

I am attempting to duplicate an entry. That part isn't hard. The tricky part is: there are n entries connected with a foreign key. And for each of those entries, there are n entries connected to that. I did it manually using a lookup to duplicate and cross reference the foreign keys.
Is there some subroutine or method to duplicate an entry and search for and duplicate foreign entries? Perhaps there is a name for this type of replication I haven't stumbled on yet, is there a specific database related title for this type of operation?
PostgreSQL 8.4.13
main entry (uid is serial)
uid | title
-----+-------
1 | stuff
department (departmentid is serial, uidref is foreign key for uid above)
departmentid | uidref | title
--------------+--------+-------
100 | 1 | Foo
101 | 1 | Bar
sub_category of department (textid is serial, departmentref is foreign for departmentid above)
textid | departmentref | title
-------+---------------+----------------
1000 | 100 | Text for Foo 1
1001 | 100 | Text for Foo 2
1002 | 101 | Text for Bar 1
You can do it all in a single statement using data-modifying CTEs (requires Postgres 9.1 or later).
Your primary keys being serial columns makes it easier:
WITH m AS (
INSERT INTO main (<all columns except pk>)
SELECT <all columns except pk>
FROM main
WHERE uid = 1
RETURNING uid AS uidref -- returns new uid
)
, d AS (
INSERT INTO department (<all columns except pk>)
SELECT <all columns except pk>
FROM m
JOIN department d USING (uidref)
RETURNING departmentid AS departmentref -- returns new departmentids
)
INSERT INTO sub_category (<all columns except pk>)
SELECT <all columns except pk>
FROM d
JOIN sub_category s USING (departmentref);
Replace <all columns except pk> with your actual columns. pk is for primary key, like main.uid.
The query returns nothing. You can return pretty much anything. You just didn't specify anything.
You wouldn't call that "replication". That term usually is applied for keeping multiple database instances or objects in sync. You are just duplicating an entry - and depending objects recursively.
Aside about naming conventions:
It would get even simpler with a naming convention that labels all columns signifying "ID of table foo" with the same (descriptive) name, like foo_id. There are other naming conventions floating around, but this is the best for writing queries, IMO.

SQL Server 2008 localization of tables

I need to localize a SQL Server 2008 database. After investigating recommendations, I have found that it is best to have separate tables or each of the languages for the strings. That way different sorting settings can be set for each table. For example, a typical Product table has ProdID, Product Description, and Price fields. The recommended solution is to set the table structures to have the Product table be ProdID and Price. Then a specific table for each language would have the following structure: ProdID and Description.
My question is how do I create a store procedure that has a parameter which passes in the culture to use for the sub-table and then use that to join the tables? The sub-table needs to change based on the parameter. How can that be done? I am using SQL Server 2008.
First off, are you sure you really want to implement different tables for each culture? It would make more sense to modify your Product table to remove the description, and then add a ProductDescription table with a ProdID, culture, and description field. This way you don't have to toy around with dynamic SQL (which is what you'll have to use) to select the correct table based on the culture parameter.
...specific table for each language would have the following structure: ProdID and Description.
...which is why you're having to look at a really involved setup to get your information out of the database.
A better approach would be to use a single table, and use a code for the language. You don't want to be defining a column per attribute you want translated either, so you'd be looking at implementing something like:
LANGUAGES table
LANGUAGE_ID, pk
LANGUAGE_DESCRIPTION
Example data:
LANGUAGE_ID | LANGUAGE_DESCRIPTION
------------------------------------
1 | ENGLISH
2 | FRENCH
TRANSLATED_ATTRIBUTES table
TRANSLATED_ATTRIBUTE_ID, pk
TRANSLATED_ATTRIBUTE_DESC
Example data:
TRANSLATED_ATTRIBUTE_ID | TRANSLATED_ATTRIBUTE_DESC
------------------------------------
1 | PROD_ID
2 | PROD_DESC
LOCALIZATIONS table
LANGUAGE_ID, pk
TRANSLATED_ATTRIBUTE_ID, pk
TRANSLATED_VALUE
Example data:
LANGUAGE_ID | TRANSLATED_ATTRIBUTE_ID | TRANSLATED_VALUE
----------------------------------------------------------
1 | 1 | Product ID
2 | 1 | Produit ID
You'll want a table associating the TRANSLATED_ATTRIBUTE_ID with a given item - Product is the example you've given so:
ATTRIBUTES table
ATTRIBUTE_ID, pk
ATTRIBUTE_TYPE_CODE, fk
TRANSLATED_ATTRIBUTE_ID, fk
Example data:
ATTRIBUTE_ID | ATTRIBUTE_TYPE_CODE | TRANSLATED_ATTRIBUTE_ID
----------------------------------------------------------------
1 | PRODUCT | 1
If you want to relate on a per product basis:
ATTRIBUTES table
ATTRIBUTE_ID, pk
PRODUCT_ID, fk
TRANSLATED_ATTRIBUTE_ID, fk
Now can you use two parameters - the language (English) & what the item is (Product):
SELECT t.translated_attribute_desc,
t.translated_value
FROM LOCALIZATIONS t
JOIN TRANSLATED_ATTRIBUTES ta ON ta.translated_attribute_id = t.translated_attribute_id
JOIN ATTRIBUTES a ON a.translated_attribute_id = ta.translated_attribute_id
JOIN ATTRIBUTE_TYPE_CODES atc ON atc.attribute_type_code = a.attribute_type_code
JOIN LANGUAGES lang ON lang.language_id = t.language_id
WHERE lang.language_description = 'ENGLISH' --alternate: lang.language_id = 1
AND atc.attribute_type_code = 'PRODUCT'
You can pivot the data as necessary.

Remove rows NOT referenced by a foreign key

This is somewhat related to this question:
I have a table with a primary key, and I have several tables that reference that primary key (using foreign keys). I need to remove rows from that table, where the primary key isn't being referenced in any of those other tables (as well as a few other constraints).
For example:
Group
groupid | groupname
1 | 'group 1'
2 | 'group 3'
3 | 'group 2'
... | '...'
Table1
tableid | groupid | data
1 | 3 | ...
... | ... | ...
Table2
tableid | groupid | data
1 | 2 | ...
... | ... | ...
and so on. Some of the rows in Group aren't referenced in any of the tables, and I need to remove those rows. In addition to this, I need to know how to find all of the tables/rows that reference a given row in Group.
I know that I can just query every table and check the groupid's, but since they are foreign keys, I imagine that there is a better way of doing it.
This is using Postgresql 8.3 by the way.
DELETE
FROM group g
WHERE NOT EXISTS
(
SELECT NULL
FROM table1 t1
WHERE t1.groupid = g.groupid
UNION ALL
SELECT NULL
FROM table1 t2
WHERE t2.groupid = g.groupid
UNION ALL
…
)
At the heart of it, SQL servers don't maintain 2-way info for constraints, so your only option is to do what the server would do internally if you were to delete the row: check every other table.
If (and be damn sure first) your constraints are simple checks and don't carry any "on delete cascade" type statements, you can attempt to delete everything from your group table. Any row that does delete would thus have nothing reference it. Otherwise, you're stuck with Quassnoi's answer.