Linking or Mapping two tables together - sql

Consider my data as inventory list separated by categories.
When I started I had one table that should have been split into two tables, else in the oldTable the columns in a given row would have been un-related. I have created two new tables in my database, one for categories and the other for data/items. Now I am trying to use the oldTable existing data to fill the newTable data/items table so I can learn SQL and not have to manually do it. The categories table I filled in manually because I could not see how to do it otherwise.
The old table has:
tableName (
id,
categoryA,
categoryB,
categoryC,
categoryD,
categoryE,
categoryF,
isPriorityA,
isPriorityB,
isPriorityC,
isPriorityD,
isPriorityE,
isPriorityE
)
The new tables have:
Categories (
cat_id,
name
)
dataItem (
item_id,
cat_id,
name,
priority,
description,
URL
)
How do I force the new dataItem table to require the cat_id match one of the values in the Categories.cat_id table column? Perhaps to give an error if a value is added outside of the range? I believe this may be mapping or linking tables, to thereby make them relationship tables.
How do I copy the tableName data to the dataItem table one column at a time in alphabetical order bringing the name,priority with it and allowing it to auto-increment the item_id value?

Sounds like you want to use a foreign key to limit dataItem.cat_id to values in Categories.cat_Id. Something like this:
ALTER TABLE dataItem ADD FOREIGN KEY (cat_id) REFERENCES Categories(cat_id);
Exact syntax may depend on which database you are using. For more info on foreign keys see: http://www.w3schools.com/sql/sql_foreignkey.asp

Related

How do I move a field to a different table and maintain relationships?

I figure this has to be easy, I'm just not sure how to ask the question.
I have thousands of records I imported from a Excel Spreadsheet in a Microsoft Access table with a field that I want to extract into a new table. How do I move the data from the field in the existing table to a new table and maintain the relationships to the record?
The goal is to move the existing data from the one field into a new table that will have a one-to-many relationship with the existing parent table.
For example, in a table called tblProperties I have the following fields:
Property_Address | Property_Owner | UtilityMeter_Number
I want to maintain a history of utility meters on properties as they are replaced, so I want to move the UtilityMeter_Number field from tblProperties into a new table called tblMeters and create a one-many relationship between the two so I can have multiple meter records for each property record.
How do I move all the existing data from the UtilityMeter_Number field in tblProperties into tblMeters, and maintain the relationship?
What is what I'm trying to do called, and how do I do it?
This is called normalizing data structure.
Use a SELECT DISTINCT query to create unique records. Use that dataset as source to create a new table. Something like:
SELECT DISTINCT CustID, LName, FName, MName INTO Customers FROM Orders;
Now delete unnecessary LName, FName, MName fields from Orders table.
Tables are related on the common CustID fields. An autonumber primary key is not utilized. If you do want a relationship on autonumber PK, then continue with following steps:
add an autonumber field in new table
create a number field in original table
run an UPDATE action SQL to populate new number field with autonumber value from new table - join tables on common CustID fields
also delete CustID field from original table

Assign unique ID to duplicates in Access

I had a very big excel spreadsheet that I moved into Access to try to deal with it easier. I'm very much a novice. I'm trying to use SQL via Access.
I need to assign a unique identifier to duplicates. I've seen people use DENSE_RANK in SQL but I can't get it to work in Access.
Here's what I'm trying to do: I have a large amount of patient and sample data (20k rows). My columns are called FULL_NAME, SAMPLE_NUM, and DATE_REC. Some patients have come in more than once and have multiple samples. I want to give each patient a unique ID that I want to call PATIENT_ID.
I can't figure out how to do this, aside from typing it out on each row. I would greatly appreciate help as I really don't know what I'm doing and there is no one at my work who can help.
To illustrate the previous answers' textual explanation, consider the following SQL action queries which can be run in an Access query window one by one or as VBA string queries with DAO's CurrentDb.Execute or DoCmd.RunSQL. The ALTER statements can be done in MSAcecss.exe.
Create a Patients table (make-table query)
SELECT DISTINCT s.FULL_NAME INTO myPatientsTable
FROM mySamplesTable s
WHERE s.FULL_NAME IS NOT NULL;
Add an autonumber field to new Patients table as a Primary Key
ALTER TABLE myPatientsTable ADD COLUMN PATIENT_ID AUTOINCREMENT NOT NULL PRIMARY KEY;
Add a blank Patient_ID column to Samples table
ALTER TABLE mySamplesTable ADD COLUMN PATIENT_ID INTEGER;
Update Patient_ID Column in Samples table using FULL_NAME field
UPDATE mySamplesTable s
INNER JOIN myPatientsTable p
ON s.[FULL_NAME] = p.[FULL_NAME]
SET s.PATIENT_ID = p.PATIENT_ID;
Maintain third-norm principles of relational databases and remove FULL_NAME field from Samples table
ALTER TABLE mySamplesTable DROP COLUMN FULL_NAME;
Then in a separate query, add a foreign key constraint on PATIENT_ID
ALTER TABLE mySamplesTable
ADD CONSTRAINT PatientRelationship
FOREIGN KEY (PATIENT_ID)
REFERENCES myPatientsTable (PATIENT_ID);
Sounds like FULL_NAME is currently the unique identifier. However, names make very poor unique identifiers and name parts should be in separate fields. Are you sure you don't have multiple patients with same name, e.g. John Smith?
You need a PatientInfo table and then the SampleData table. Do a query that pulls DISTINCT patient info (apparently this is only one field - FULL_NAME) and create a table that generates unique ID with autonumber field. Then build a query that joins tables on the two FULL_Name fields and updates a new field in SampleData called PatientID. Delete the FULL_Name field from SampleData.
The command to number rows in your table is [1]
ALTER TABLE MyTable ADD COLUMN ID AUTOINCREMENT;
Anyway as June7 pointed out it might not be a good idea to combine records just based on patient name as there might be duplicates. Better way will be treat each record as unique patient for now and have a way to fix patient ID when patient comes back. I would suggest to go this way:
create two new columns in your samples table
ID with autoincrement as per query above
patientID where you will copy values from ID column - for now they will be same. But in future they will diverge
copy columns patientID and patientName into separate table patients
now you can delete patientName column from samples table
add column imported to patients table to indicate, that there might be some other records that belong to this patient.
when patients come back you open his record, update all other info like address, phone, ... and look for all possible samples record that belong to him. If so, then fix patient id in those records.
Now you can switch imported indicator because this patient data are up to date.
After fixing patientID for samples records. You will end up with patients with no record in samples table. So you can go and delete them.
Unless you already have a natural key you will be corrupting this data when you run the distinct query and build a key from it. From your posting I would guess a natural key would be SAMPLE_NUM. Another problem is that if you roll up by last name you will almost certainly be combining different patients into one.

Avoid CASE clause while importing data to SQL Server

I have to import data from an old schema to a new one, where a column 'career_name' (in table 'users') that used to be a VARCHAR now should be an INTEGER which is a foreign key to another table careers. This way I intend to tipify the data that was stored in the VARCHAR column in order to keep integrity in my database.
Actually, I do the following:
Create both new tables in the new schema
Use SELECT DISTINCT 'career_name' FROM old_table in order to obtain all possible values
INSERT into my new table careers the rows obtained above
INSERT data into my new table users using a CASE clause in order to obtain the ID from table careers of the corresponding former career_name so the relation is created.
Now the problem is the following, the table careers is big, so writing one CASE clause for each row in the table in order to import users is nearly impossible.
Is there a way to avoid this? I wish I could use my table careers as an associative array, where the key was the former career_name and the value the row's ID... Thanks!
INSERT into new_Users
SELECT Users.Name, careers.id
FROM Users inner join careers ON Users.career_name = careers.career_name
Because the schema isnt known to me, I am assuming that new_users table has 2 columns which is name and career_id.
Is there a way to avoid this? I wish I could use my table 'careers' as an associative array, where the key was the former 'career_name' and the value the row's ID... Thanks!
Er... That's what a table is, isn't it? Just join to your new careers table to use it as a lookup when doing the insert:
INSERT INTO users (blah, whatever, career_id)
SELECT
old_users_table.blah,
old_users_table.whatever,
careers.career_id
FROM
old_users_table INNER JOIN careers ON old_users_table.career_name = careers.career_name
... where users is your new users table, old_users_table is wherever you're getting the data you want to migrate, and careers is your new careers table.

SQL Refactoring - Unique Names to UniqueIdentifiers

I am in the midst of refactoring my database to support an upgrade to our web-based tool.
Imagine that I have four tables: Milestones, Categories, Skills, and PayRates. Under the old schema, each of these tables only listed a name, and that name was the key for the table.
Under the new schema, each table has not only a name, but also a generated uniqueidentifier that serves as the key for the table.
Now, also imagine that I have a table Tasks, where each Task consists of a name, a Milestone, a Category, a Skill, and a PayRate, and each of these is selected from their respective tables. Under the old schema, this table only stored names. Under the new schema, this table will store the IDs for the four tables instead of the names, like the following:
TaskID TaskName MilestoneID CategoryID SkillID RateID
where TaskID is a generated uniqueidentifier for that Task.
Each of these tables currently contains data that needs to be transferred from the old schema to the new schema. I can assume that names of each of the four components of Tasks, and the names of Tasks themselves, are unique in the old schema.
My question is, what is the simplest query to move the data from the old schema into the new one?
This is being done to support storing two separate lists of Milestones, Tasks, etc. in the same database.
I'd do the following
Step zero: Backup your database
Step one: Add the unique identifiers to Milestones, Categories, Skills and PayRates. This is a simple column addition with default value the next id. This will generate your identifiers for the existing names.
Step two: Add the four new columns to the existing task table (and add foreign keys to the source tables if desired), without deleting the old, name pointing columns.
Step three: Run (assuming the old, name pointing columns are called Milestone, Skill and so on)
update Tasks set MilestoneID = (
select MilestoneID from Milestones where
Milestone = Tasks.Milestone
),
CategoryID = (
select CategoryID from Categories where
Category = Tasks.Category
),
SkillID = (
select SkillID from Skills where
Skill = Tasks.Skill
),
PayRateID = (
select PayRateID from PayRates where
PayRate = Tasks.PayRate
)
Step four: Check everything is in place
Step five: Delete old columns from Tasks table, make new fields non-null

How to transform SQL table of data into table of pointers?

Let's say I have an SQL table of tuples (id, lastname, firstname, occupation) where all values are strings (ok, obviously id is a key).
I want to transform it to a table with tuples (id, lastid, firstid, occupid), where I only keep pointers to other tables that contain the actual values. I apologize if the example domain of names and occupations is not the best suited for this operation.
Obviously to create the other tables that will hold the data, I need to get all last names, unique, and insert them into a new table with an auto-generated key. The same with first names and occupations.
Having done that, is there a single transformation that can generate the new table containing the pointers (er, foreign keys) ?
Implementation uses SQLite, if it matters.
Assuming your tables for last/first names and occupations are Lnt, Fnt and Occ, each with just two columns, an id field and a value:
REPLACE INTO TheTable (last, first, occup)
SELECT Lnt.id, Fnt.id, Occ.id
FROM TheTable
JOIN Lnt ON (last=Lnt.value)
JOIN Fnt ON (first=Fnt.value)
JOIN Occ ON (occup=Occ.value)