enforce primary key to exist in another multi colum primary key - sql

I have two tables. First table has multi columns as the primary key and the second table has one column primary key. Data has be entered first in Table1 FieldPlacement where FieldPlacementNum will be generated then enter a record in Table2 where the FieldPlacementNum has to exist in Table1.
Currently has one to many relationship but I want the reverse the relationship of tables and SQL does not let me do it. thanks
Table 1
CREATE TABLE [dbo].[FieldPlacement]
(
[ID] [varchar](10) NOT NULL,
[Year] [varchar](10) NOT NULL,
[Term] [varchar](10) NOT NULL,
[PlacementNum] [int] IDENTITY(1,1) NOT NULL,
[Email] [varchar](70) NULL,
CONSTRAINT [PK_FieldPlacement]
PRIMARY KEY CLUSTERED ([ID] ASC, [Year] ASC, [Term] ASC, [PlacementNum] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[FieldPlacement] WITH CHECK
ADD CONSTRAINT [FK_FieldPlacement_FieldPlacementEval1]
FOREIGN KEY([PlacementNum])
REFERENCES [dbo].[FieldPlacementEval] ([PlacementNum])
GO
ALTER TABLE [dbo].[FieldPlacement]
CHECK CONSTRAINT [FK_FieldPlacement_FieldPlacementEval1]
GO
Table 2
CREATE TABLE [dbo].[FieldPlacementEval]
(
[PlacementNum] [int] NOT NULL,
[StudentLastName] [varchar](50) NULL,
[StudentFirstName] [varchar](50) NULL,
[TeacherLastName] [varchar](50) NULL,
[TeacherFirstName] [varchar](50) NULL,
CONSTRAINT [PK_FieldPlacementEval]
PRIMARY KEY CLUSTERED ([PlacementNum] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

Since FieldPlacement.PlacementNum is an IDENTITY, which is NOT NULL and unique, you could also make this your PK, and then just create a unique index on those four columns that currently make up the PK (to ensure their uniqueness).
From your FieldPlacementEval just reference the PlacementNum.
The additional benefit here would be a smaller, more efficient clustering key on your FieldPlacement table (since it's only 1 column instead of 4 - and skips all those variable length columns which are really bad for a clustering key)

Related

Azure SQL - creating an autogenerating id with a constraint causing issues for powerapps

When using the below SQL, I get the error "Incorrect syntax near 'WITH'."
SQL statement with key and autogenerate id:
CREATE TABLE [dbo].[Stopwords](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Stopword] [nvarchar](150) NULL,
[Timestamp] [nvarchar](17) NULL,
[Created by] [nvarchar](150) NULL,
CONSTRAINT [PK_StopwordsId] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
) ON [PRIMARY]
GO
I need an autogenerating id so that I can write to the table using PowerApps. Without the constraints, PowerApps will not recognize the autogenerating ID and allow me to use the table. I think once I get the constraint in place, I will be able to get PowerApps connected properly. I am following instructions from this video https://youtu.be/193b7T_p35M?t=9m56s and at 10 min she discusses the importance of the autogenerating key.
With PowerApps you only need a primary key in your SQL table, so you can use a simpler version of your create table statement:
CREATE TABLE [dbo].[Stopwords] (
[Id] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
[Stopword] [nvarchar](150) NULL,
[Timestamp] [nvarchar](17) NULL,
[Created by] [nvarchar](150) NULL
)
This table can be accessed by PowerApps.

How to set hierarchic foreign key through another table?

I am not sure if my title really explains the question, so I'll try an example:
Let's say I have:
1) region table: parent regions and subregions in the same table (link A)
2) product table: each product is linked to a single parent region (link B)
3) product_price table: lists the price of a product (C) in all sub regions of that product region (link D >>> the link in question).
(the diagram is showing only the relevant fields, there are a lot more data in region and product)
Is there a way to define the region->region_price key, to include only sub_region_id's of the parent_region in the product->region key??
Or, in the terms of the image, how do I make the D link to include only regions that are children [as in A] of the B & C link?
Hope you are getting my point...
Here are the real tables and links:
CREATE TABLE [dbo].[product](
[product_id] [int] NOT NULL,
[product_name] [nchar](10) NOT NULL,
[parent_region_id] [int] NOT NULL,
CONSTRAINT [PK_product] PRIMARY KEY CLUSTERED
(
[product_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE TABLE [dbo].[product_price](
[product_id] [int] NOT NULL,
[sub_region_id] [int] NOT NULL,
[price] [decimal](18, 0) NOT NULL,
CONSTRAINT [PK_product_price] PRIMARY KEY CLUSTERED
(
[product_id] ASC,
[sub_region_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE TABLE [dbo].[region](
[region_id] [int] NOT NULL,
[region_name] [nvarchar](50) NOT NULL,
[parent_region_id] [int] NULL,
CONSTRAINT [PK_region] PRIMARY KEY CLUSTERED
(
[region_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
ALTER TABLE [dbo].[product] WITH CHECK ADD CONSTRAINT [FK_product_region] FOREIGN KEY([parent_region_id])
REFERENCES [dbo].[region] ([region_id])
ALTER TABLE [dbo].[product] CHECK CONSTRAINT [FK_product_region]
ALTER TABLE [dbo].[product_price] WITH CHECK ADD CONSTRAINT [FK_product_price_product] FOREIGN KEY([product_id])
REFERENCES [dbo].[product] ([product_id])
ALTER TABLE [dbo].[product_price] CHECK CONSTRAINT [FK_product_price_product]
ALTER TABLE [dbo].[product_price] WITH CHECK ADD CONSTRAINT [FK_product_price_region] FOREIGN KEY([sub_region_id])
REFERENCES [dbo].[region] ([region_id])
ALTER TABLE [dbo].[product_price] CHECK CONSTRAINT [FK_product_price_region]
ALTER TABLE [dbo].[region] WITH CHECK ADD CONSTRAINT [HK_region_region] FOREIGN KEY([parent_region_id])
REFERENCES [dbo].[region] ([region_id])
ALTER TABLE [dbo].[region] CHECK CONSTRAINT [HK_region_region]
I guess you are trying to enforce a business rule with a database rule, but they're not always the same. Instead, you can run validation querys in your code before inserting or updating, or you could implement a trigger that validates your rules or throws an error.

Relationships in SQL on the same table

I haven't ever really used foreign keys in my databases, I have always just written code that would enforce things for me, but I'm looking towards shifting some of that logic to the database and learning more about foreign keys.
I currently have a database which has the table Categories:
CREATE TABLE [dbo].[Categories](
[CategoryID] [bigint] IDENTITY(1,1) NOT NULL,
[ParentCategoryID] [bigint] NOT NULL,
[CategoryStatus] [bit] NOT NULL,
[CategoryTitle] [varchar](64) NOT NULL,
[CategorySlug] [varchar](64) NOT NULL,
[CategoryThumbnail] [varchar](128) NULL,
[CategoryHeaderImage] [varchar](128) NULL,
[CategoryDescription] [text] NULL,
CONSTRAINT [PK_Categories] PRIMARY KEY CLUSTERED
(
[CategoryID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
CONSTRAINT [UI_Categories_Slug] UNIQUE NONCLUSTERED
(
[CategorySlug] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
I would like to create a foreign key that relates ParentCategoryID back up to CategoryID. When creating the FK, which would be the primary column, and which would be the foreign column in this instance?
I would think that ParentCategoryID would have to be NULLable (unless you want a top-level parent to point to itself, and that doesn't make much sense).
ALTER TABLE dbo.Categories
ADD CONSTRAINT FK_SelfParent
FOREIGN KEY (ParentCategoryID)
REFERENCES dbo.Categories(CategoryID);
True story: at a job interview at Microsoft (several years ago), a SQL Server person told me that this wasn't possible.

How to Insert into 2 Tables ProductOrder and ProductOrderLine using VBA & Foreign Keys in Excel

I am newbiew using VBA/FK/SQL server all in one. I am creating simple purchase order workbook user interface in excel.
I have created two tables:
CREATE TABLE [dbo].[PurchaseOrder](
[PKPurchaseOrderID] [bigint] IDENTITY(1,1) NOT NULL,
[PurchaseOrderNumber] [bigint] NULL,
[PurchaseOrderDate] [date] NULL,
[PurchaseOrderTime] [int] NULL,
[PurchaseOrderSupplierID] [nvarchar](50) NULL,
[ShipToA1] [nvarchar](50) NULL,
[ShipToA2] [nvarchar](50) NULL,
[ShipToA3] [nvarchar](50) NULL,
[ShipToA4] [nvarchar](50) NULL,
CONSTRAINT [PK_PurchaseOrder] PRIMARY KEY CLUSTERED
(
[PKPurchaseOrderID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
and
CREATE TABLE [dbo].[PurchaseOrderLines](
[PKPurchaseOrderLineID] [bigint] IDENTITY(1,1) NOT NULL,
[FKPurchaseOrderID] [bigint] NULL,
[Quantity] [smallint] NULL,
[Item] [nchar](25) NULL,
[Description] [nvarchar](50) NULL,
[siteID] [nchar](10) NULL,
[UnitPrice] [money] NULL,
[LineTotal] [money] NULL,
CONSTRAINT [PK_PurchaseOrderLines] PRIMARY KEY CLUSTERED
(
[PKPurchaseOrderLineID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
ALTER TABLE [dbo].[PurchaseOrderLines] WITH CHECK ADD CONSTRAINT
[FK_PurchaseOrderLines_PurchaseOrder] FOREIGN KEY([FKPurchaseOrderID])
REFERENCES [dbo].[PurchaseOrder] ([PKPurchaseOrderID])
ALTER TABLE [dbo].[PurchaseOrderLines] CHECK CONSTRAINT
[FK_PurchaseOrderLines_PurchaseOrder]
GO
I want to achieve that in the background when user clicks the button both tables are updated.
I am not sure how I can link brand new row created in the PurchaseOrder table with FK in the PurchaseorderLine table.
What i plan to do for single user interface:
Insert New Order
Use Max(PKPurchaseOrderID) as FK for new order lines table.
How can I determine currently inserted Order ID(PKPurchaseOrderID) if multiple users are working/submitting orders at the same time. I am afraid order lines may be assigned to different orders if I use my plan. e.g.
Please advise.
I use SQL Server 2008 and Excel 2007/2010
Many thanks
I would create a stored procedure that inserts the new row and returns the ID with SCOPE_IDENTITY()
Here's a decent article on the different "identity" methods in SQL Server.
http://blog.sqlauthority.com/2007/03/25/sql-server-identity-vs-scope_identity-vs-ident_current-retrieve-last-inserted-identity-of-record/

How do you add Foreign Key Relationships?

I'm working with an existing SQL 2005 database that was not implemented with FK relationships between tables. I tried to add the relationships with a database diagram and my application immediately blew up trying to edit or insert any data that is tied to the new FK.
dbo.person [person_id | firstname | lastname | dateofbirth]
dbo.campaign [campaign_id | campaign_description]
dbo.disposition [disposition_id | disposition_description]
dbo.person_campaigns [person_campaign_id | person_id | campaign_id | disposition_id]
The person_campaigns table is where a person, campaign, and disposition are tied together. Can you please provide the appropriate SQL syntax for adding the proper FK relationships between these entities?
EDIT
CREATE TABLE [dbo].[person_campaigns](
[person_campaigns_id] [int] IDENTITY(1,1) NOT NULL,
[person_id] [int] NOT NULL,
[d_campaign_id] [int] NOT NULL,
[d_physician_disposition_id] [int] NULL,
CONSTRAINT [PK_person_campaigns] PRIMARY KEY CLUSTERED
(
[person_campaigns_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[d_campaign](
[d_campaign_id] [int] IDENTITY(1,1) NOT NULL,
[name] [varchar](50) NULL,
[year] [int] NULL,
[isactive] [bit] NOT NULL,
CONSTRAINT [PK_d_campaign] PRIMARY KEY CLUSTERED
(
[d_campaign_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[d_campaign] ADD CONSTRAINT [DF_d_campaign_isactive] DEFAULT ((1)) FOR [isactive]
GO
CREATE TABLE [dbo].[d_disposition](
[d_disposition_id] [int] IDENTITY(1,1) NOT NULL,
[name] [varchar](50) NULL,
[isactive] [bit] NOT NULL,
CONSTRAINT [PK_d_disposition] PRIMARY KEY CLUSTERED
(
[d_disposition_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[d_disposition] ADD CONSTRAINT [DF_d_disposition_isactive] DEFAULT ((1)) FOR [isactive]
GO
CREATE TABLE [dbo].[person](
[person_id] [int] IDENTITY(1,1) NOT NULL,
[firstname] [varchar](30) NULL,
[lastname] [varchar](30) NULL,
[dateofbirth] [datetime] NULL
CONSTRAINT [PK__person__0BC6C43E] PRIMARY KEY CLUSTERED
(
[person_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
the easiest way to do it is through the database diagram editor; do them one at a time and save the diagram to affect the tables after each connection is made. If it "blows up" it is most likely because the tables contain foreign-key values that do not exist; you'll have to clean these up first.
If you have to add them after the table is created the syntax is
create table person (person_id int primary key
,firstname varchar(10)
, lastname varchar(10)
, dateofbirth varchar(10))
create table campaign (campaign_id int primary key
, campaign_description varchar(10))
create table disposition (disposition_id int primary key
,disposition_description varchar(10))
create table person_campaigns(person_campaign_id int
,person_id int, campaign_id int ,disposition_id int)
go
alter table person_campaigns add Constraint
fk_person_campaigns_person_id
Foreign Key (person_id) References person(person_id)
GO
alter table person_campaigns add Constraint
fk_person_campaigns_campaign_id
Foreign Key (campaign_id) References campaign(campaign_id)
GO
alter table person_campaigns add Constraint
fk_person_campaigns_disposition_id
Foreign Key (disposition_id) References disposition(disposition_id)
GO
Suppose I had two tables that should have had a foreign key but did not. The first thing to do is check to see if there will be a data problem if I set a foreign key.
something like the below code would get you the records in the child table that do not have a match in the parent table.
select t2.FKField, t2.PKfield from table2 t2
left join Table1 t1 on t2.fkfield = t1.pkfield
where t1.pkfield is null
Once you can see what is wrong with the existing data, then you need to create a way to fix it. The fix will vary depending on what data you have that has no relationship to the Parent table and what the tables represent. Suppose your parent table contained a VIN number for automobiles as the PK. If your child table contains the cars that were worked on by the shop, you would want to fix the issue by adding the nonexisting VINS to the primary table becasue you wouldn't want to lose the history of what was worked on. There are other structures where you might want to simply delete the records that don't match in child table because they are meaningless. In other circumstances you might want to update those records to some default value (perhaps a customer in the customer table called unknown). In still other circumstances, you might need to go to audit tables or backups to find the value of the PK that was deleted without the associated child records being deleted. The actual way to fix this problem is highly dependent on what the data is used for and how important it is to retain all historical records. Since you should never delete any record that might be related to a financial transaction for legal (and accounting) reasons, you need to be most careful with those.
After fixing all the data, then you run the code to create the FK constraint.
Since I don't have SQL Server on this PC and I don't memorize the syntax, the easiest thing to do is to create two new test tables, create TableA with an ID field, TableB with a field that is a FK of TableA.ID, and then script out TableB to see the ADD CONSTRAINT syntax. Do this using SQL Server Management Studio via a database diagram.
However, if you were able to successfully create the FKs in a data diagram, and you only can't add or update records, I believe something else is wrong. Script out the person_campaigns table and post the code.