use foreign key constraint to ensure valid data entry - sql

I have been cleaning up a database table which was bit of a nightmare.
I want to ensure that the data being entered going forward is correct. So I read about foreign key constraints.
So below is a table where the data gets entered into.
tblSales
Country Seller Value
52 01 100
86 01 100
102 32 100
32 52 100
52 01 100
I want to ensure the values being entered into the Country & Seller fields are a certain set of values. There is also a table called tblMap which is used for reports to give the numbers a name which is easy to read.
tblMap
Factor Code Name
Country 52 US
Country 86 Germany
Country 102 Spain
Country 32 Italy
Seller 01 Bob
Seller 32 Sarah
Seller 52 Jim
So like I say I was going to use a foreign key constraint but I can't create a primary key on the Code field in tblMap as 52 is used for both a country and a seller. I am not able to change the code numbers either.
Am I still able to use a foreign key constrain to ensure any value entered into tblSales exists in tblMap?

May be you can replace tblMap by 2 tables tblMapCountry and tblMapSeller
tblMapCountry
Code Name
52 US
86 Germany
102 Spain
32 Italy
tblMapSeller
Code Name
01 Bob
32 Sarah
52 Jim
After you can base
a FK between tblSales.country and tblMapCountry
a FK between tblSales.seller and tblMapSeller
At the end you can build a view tblMap by union the 2 tables tblMapCountry and tblMapSeller
create view `tblMap`
as
select 'Country' as Factor,Code,Name from tblMapCountry
union all
select 'Seller' as Factor,Code,Name from tblMapSeller

Related

How to join a fact table to a dimension table which has a duplicate key value while avoiding duplications in fact table?

How do I join a fact table to a dimension table with a duplicate key value, while at the same time avoiding duplication in the fact table that would result from the join?
Dimension table: enter image description here
fact table: enter image description here
product look-up table (another dimension table): enter image description here
I thought of using the activation date as the next unique value, but they share a month in common.
I thought of creating a snowflake schema which connects dimension table in question (marketing campaigns) to product dimension which in turn connects to the fact table with no issues.
edit:
I am designing a datawarehouse which should answer how effective marketing campaigns based on purchase data.
Purchase data which will be the core of my fact table looks like this:
product_id timestamp sales_price user_id
1 5/9/2015 120 124
2 6/9/2015 150 129
the product lookup table looks like this:
id product_name model production_cost
6 ring 2019 300
5 headband 2018 200
the marketing campaigns look up table looks like this:
startdate enddate type amount_spent currency product_id
1/1/2019 7/1/2019 print 100,000 USD 6
6/1/2019 1/1/2020 socialmedia 10,000,000 USD 6
6/1/2019 1/1/2020 socialmedia 10,000,000 USD 3
The issue is that the marketing table has duplicate product id value of 6. So, when I use it as my natural key to create a surrogate primary key for that dimension table and pull that surrogate key to the fact table as a foreign key it's going to cause duplications for anything with product_id of 6 (as it's not unique). How do I connect marketing campaigns data to fact table, whilst keeping the data integrity intact -- that is no duplications?
I thought about combining start/end date with product_id to create a composite primary key, but they share/overlap a month (6/1/2019 to 7/1/2019)
I also thought about connecting the purchases (fact table) to product lookup and then product to marketing campaigns (a snowflake schema) to avoid the duplication.
I suggest you take the time to read the details of dimensional database design.
If you mean dimensional design, there is no such thing as a lookup table there; there is either a Slowly Changing Dimension (SCD), or just a Dimension. Your product lookup table could be a product lookup dimension. Your Dimension table looks imperfect, too: It does contain the element of time , but not correctly. You need - usually in this order:
a completely arbitrary integer as a surrogate, primary, key - often populated by a sequence or defined as IDENTITY
a business identifier - that could be the SKU for a product, first part of a business unique identifier
the valid-from-date, second part of a business unique identifier
the valid-to-date, '9999-12-31' for the current row, or equal to the valid-from-date of its successor
Type 1 attributes, those that don't change over time
Type 2 attributes, those that change over time and need a new row every time they change
There can be more columns: the Boolean current-indicator, and an inserted timestamp and an updated timestamp.
The fact table is populated from the source transactions, after the dimension table. For each transaction row, you join with the SCD table with the business identifier (SKU in our case), that must be equal and the transaction's timestamp, that must be greater or equal to the valid-from-date and less than the valid-to-date. You pick the surrogate key of the row found in the SCD to populate the fact table's foreign key.
This is an exemplary, minimal, customer SCD table, without the insert/change timestamps and without the current-indicator:
c_key
c_id
c_from_dt
c_to_dt
c_fname
c_lname
c_loy_lvl
c_org_id
66459
1
2022-01-25
9999-12-31
Arthur
Dent
1
1
34168
2
2022-01-25
9999-12-31
Ford
Prefect
2
2
2284
3
2021-12-25
9999-12-31
Zaphod
Beeblebrox
3
3
84768
4
2021-12-25
9999-12-31
Tricia
McMillan
4
4
80080
5
2022-01-25
9999-12-31
Gag
Halfrunt
5
5
57458
6
2022-01-25
9999-12-31
Prostetnic Vogon
Jeltz
6
6
1076
7
2022-01-25
9999-12-31
Lionel
Prosser
1
0
9782
8
2021-12-25
9999-12-31
Benji
Mouse
2
1
42655
9
2021-12-25
9999-12-31
Frankie
Mouse
3
2
57348
10
2021-09-25
2021-10-25
Wonko
The Sane
1
3
22279
10
2021-10-25
2021-11-25
Wonko
The Sane
2
3
3675
10
2021-11-25
2021-12-25
Wonko
The Sane
3
3
95534
10
2021-12-25
2022-01-25
Wonko
The Sane
4
3
69529
10
2022-01-25
9999-12-31
Wonko
The Sane
5
3
34845
11
2022-01-25
9999-12-31
Eccentrica
Gallumbitis
6
4

How to add values to single empty column from local text file

I have table called customers with CustomerID,CompanyName,Address,Phone
Now we inserted a new column called Remarks which is empty or null
I have text file to bulk insert into the column using the view Remarkinsert with the following code
bulk insert HRRegion.dbo.Remarksinsert
From 'C:\Users\SMSTECHLNG50\Documents\remarks..txt'
with
(
FIELDTERMINATOR = ',',
ROWTERMINATOR = '\n'
)
GO
But its getting the error
Msg 515, Level 16, State 2, Line 9 Cannot insert the value NULL into
column 'CustomerID', table 'HRRegion.dbo.Customers'; column does not
allow nulls. INSERT fails. The statement has been terminated.
I think that also here, you can only insert a whole row or nothing.
If your customer table looks like this:
customer
custid|co_name |addr |phone |remarks
42|Laverda |Breganze, Italy |+39 6 233 84 81 |(NULL)
43|Benelli |Pesaro, Italy |+39 8 284 55 32 |(NULL)
44|Ural |Irbit, Russia |+7 14 526 22 2342|(NULL)
45|Dnepr |Kiew, Ukraine |+380 526 22 2342 |(NULL)
46|Harley Davidson|Milwaukee, US |+1 802 223 4444 |(NULL)
47|Honda |Tokyo, Japan |+81 82 555 4123 |(NULL)
48|Moto Guzzi |Mandello del Lario, Italy|+39 6 423 04 72 |(NULL)
49|Ducati |Bologna, Italy |+39 7 722 04 43 |(NULL)
50|Norton |Birmingham, UK |+44 7234 723 4423|(NULL)
51|Matchless |Plumstead, London, UK |+44 8021 612 0843|(NULL)
52|Brough |Nottingham, UK |+44 5812 512 4883|(NULL)
(well, you add the remarks column using an ALTER TABLE ...), then, I would expect the file you mentioned with the remarks to look somewhat like this:
remarks
custid|remarks
42|built also tractors, closed now
43|first series 6-cylinder motorbike
44|old style sidecar rigs with modern engine
45|old style sidecar rigs, permanent two-wheel drive
46|the american classic
47|builders of the CB 750 four and the gold wing
48|famous for horizontal singles and 90° V twins
49|90° V twin bikes with lateral crankshaft
50|english classic, still alive
51|english classic, closed now
52|probably the finest motorcycles ever built
So, you would build a remarks_stg table:
CREATE TABLE remarks_stg (
custid SMALLINT NOT NULL
, remarks VARCHAR(50) NOT NULL
);
Then, you load just that staging table with the data file as described above - and, at least if have SQL Server 2008 and above, you use a MERGE statement to update the customer table:
MERGE customer t
USING stg_customer s
ON t.custid = s. custid
WHEN MATCHED THEN UPDATE SET
remarks = s.remarks
;

Create INSERT script with incrementing ID for linked tables (SQL server)

I have a regular task which involves exporting two tables from one database and importing the data into another database whose corresponding tables are not empty. One of the tables in question has a column which refers to the ID of the first. Let's call them Customer and Customer_Address where Customer_Address has a column Cust_ID referring to ID in the Customer table.
I need to create an import script for these which will add the Customer records to the other, non-empty DB with ID = max(id)+1 for each row while not breaking the link to the other table. The Customer_Address table likewise has its own ID column which needs to be incremented in the same manner.
I don't strictly need to have the first inserted record be one higher than the existing highest ID, but it would be best. I've managed in the past to manually check the highest ID in the target DB and add this number using search and replace and a variable in the import script but it's laborious and fails if any records are added to the target DB in the interim.
I have another method which involves selecting, copying, pasting and SQL-wrapping selected all columns but ID from the source tables using Excel and using select(max) instead of the ID but again it's rather tedious.
Edit with data:
Sample script to create source and destination tables (in the same/temdb database for convenience) is here:
http://pastebin.com/C64wFtsP
Should give output as follows:
select * from customer
id Last First
1 Johnson James
2 Kelly Karl
3 Lawlor Liam
select * from customer2
id Last First
1 Adams Ann
2 Byrne Bressie
3 Casey Charlene
select * from customeraddress
id idclient street city county country
1 1 65 North St. Marcoussin Jojoba Flatland
2 2 42 South St. Marcoussin Jojoba Flatland
3 3 12 West St. Marcoussin Jojoba Flatland
4 1 17 East St. Marcoussin Jojoba Flatland
5 1 75 Centre St. Marcoussin Jojoba Flatland
select * from customeraddress2
id idclient street city county country
1 1 99 North St. Marcoussin Jojoba Flatland
2 2 88 South St. Marcoussin Jojoba Flatland
3 3 88 West St. Marcoussin Jojoba Flatland
4 1 66 East St. Marcoussin Jojoba Flatland
5 1 55 Centre St. Marcoussin Jojoba Flatland
What I'm looking for is a way to script an import of the data in both source tables to the corresponding destination tables, while preserving the link between the idclient in customeraddress and the id in customer.
If you can stage data in your destination database, just do this:
Stage both tables in Destination, all fields.
Insert users into new Destination table.
Write a query like this
Note that you'll need to identify a natural key for your customers (the thing that makes them distinct entities in Customer1 that also exists in Customer2) - firstName, lastName probably isn't the best as they're highly unlikely to be distinct across your customer base, but it's what you've got in your sample data.
INSERT INTO customeraddress2
SELECT
customer2.id,
staged_customeraddress1.street,
staged_customeraddress1.city,
staged_customeraddress1.county,
staged_customeraddress1.country
FROM customer2
JOIN staged_customer1
ON staged_customer1.firstName = customer2.firstName
AND staged_customer1.lastName = customer2.lastName
JOIN staged_customeraddress1
ON staged_customeraddress1.idclient = staged_customer1.id

SQL, check user constraints

First, the table:
CLASS CLASS_NAME PROFESSOR NUMBER_OF_STUDENTS COST START_DAT END_DATE ROO
----- -------------------- ------------------ ------------------ ---------- --------- --------- ---
PC102 Peripherals Henry Higgins 12 $1,100.00 11-JAN-13 11-MAY-13 129
PC101 MS OFFICE BASICS INDIANA JONES 18 $1,000.00 10-JAN-13 10-MAY-13 127
EE101 Elementary Education Frank McCourt 22 $900.00 12-JAN-13 12-MAY-13 227
PC123 MS OFFICE ADVANCED Bill Gates 10 $800.00 13-JAN-13 13-MAY-13 180
The problem:
Add a check constraint to number of students to ensure capacity is between 12 and 25
students.
What I've tried
ALTER TABLE BW_CLASS
ADD CHECK( NUMBER_OF_STUDENTS > 15 AND
NUMBER_OF_STUDENTS < 25);
What is returned
ERROR at line 1:
ORA-02293: cannot validate (STUDENT.SYS_C007516) - check constraint violated
What am I doing wrong?
The table you're trying to apply the check to already has values that fail the check. Fix the entries in the table that fail, then apply the check.
Make sure the number of students in each class is between 12 and 25. update table, where number of students is below 12 increase to > 12. Where it's higher than 25 reduce.

Added a FK to my customer table from Bill table, can not add data to fk column

Foreign Key Not Populating with Primary Key Values
I did a lot of searching on the site, but I am relatively new to writing code for a database. I read a few threads like the one listed above, but I was unable to utilize the information within to solve my problem. I have two tables, customer and billing. The customer table is below:
SQL> SELECT * FROM CUSTOMER;
CUST_ID NAME BILL_NUM
-------------------- ------------------- ----------
432 MICHAEL MAYS
433 VILMA PACULAN
434 RUBY PUKE
435 ROWENA JOHNSON
436 MAGIC JOHNSON
437 DARTH VADER
438 OBI WAN
439 YODA
440 STEWIE GRIFFIN
441 EVIL MONKEY
442 HARRY POTTER
Bill table:
SQL> SELECT * FROM BILL
2 ;
BILL_NUM TOTAL
---------- ----------
1000 5.5
1001 7.4
1002 12.5
1003 14.56
1004 25.36
1005 66.66
1006 99.97
1007 56.67
1008 5.23
1009 87.25
1010 36.17
As you can see in the customer table the FK Bill_Num is null. I need to know how to insert the data into the column, to match the PK data? I am using oracle 10g SQLPlus. Any help would be greatly appreciated!
If you look at your current data set up, there is no common column (implicit or explicit) that would link these two tables. As a result, it is impossible to automatically link the tables.
You either need a transaction table in the form:
CUST_ID | Bill_NUM (many to many)
Or as Graeme stated put the CUST_ID on the Bill table as right now your many-to-one relationship will be the opposite of what would be expected.
http://en.wikipedia.org/wiki/Database_normalization - A good place to start on normalizing a database