একাধিক সারণীতে বিদেশী কী


127

আমার ডাটাবেসে 3 টি প্রাসঙ্গিক টেবিল পেয়েছি।

CREATE TABLE dbo.Group
(
    ID int NOT NULL,
    Name varchar(50) NOT NULL
)  

CREATE TABLE dbo.User
(
    ID int NOT NULL,
    Name varchar(50) NOT NULL
)

CREATE TABLE dbo.Ticket
(
    ID int NOT NULL,
    Owner int NOT NULL,
    Subject varchar(50) NULL
)

ব্যবহারকারীরা একাধিক গোষ্ঠীর অন্তর্ভুক্ত। এটি অনেকগুলি থেকে অনেক সম্পর্কের মাধ্যমে করা হয় তবে এই ক্ষেত্রে অপ্রাসঙ্গিক। একটি টিকিট একটি গ্রুপ বা ব্যবহারকারীর দ্বারা মালিকানা পেতে পারে dbo.Ticket.Owner ক্ষেত্রের মাধ্যমে।

টিকেট এবং allyচ্ছিকভাবে কোনও ব্যবহারকারী বা একটি গোষ্ঠীর মধ্যে এই সম্পর্কের বর্ণনা দেওয়ার সবচেয়ে সঠিক উপায় কী হবে ?

আমি ভাবছি যে টিকিটের টেবিলটিতে আমার একটি পতাকা যুক্ত করা উচিত যা এতে টাইপের মালিকানাধীন বলে।


আমার মতে প্রতিটি টিকিট একটি গ্রুপের মালিকানাধীন। এটি কেবলমাত্র একজন ব্যবহারকারী একটি দলের একটি। @ নাথান-স্কারেল মডেলগুলি থেকে 4 টি পছন্দ। আপনি যদি কী হিসাবে
নির্দেশিকাগুলি

উত্তর:


149

আপনার কাছে কয়েকটি অপশন রয়েছে, সমস্ত "নির্ভুলতা" এবং ব্যবহারের সহজতার মধ্যে পরিবর্তিত হয়। সর্বদা হিসাবে, সঠিক নকশা আপনার প্রয়োজনের উপর নির্ভর করে।

  • আপনি কেবল টিকিট, ওয়ান্ডবাইউজারআইডি এবং ওয়ান্ডবাইগ্রুপআইডিতে দুটি কলাম তৈরি করতে এবং প্রতিটি টেবিলের নিকটে অবিচ্ছিন্ন বিদেশী কী থাকতে পারে।

  • আপনি এম: এম রেফারেন্স সারণী তৈরি করতে পারেন টিকিট: ব্যবহারকারী এবং টিকিট: গ্রুপ সম্পর্ক both সম্ভবত ভবিষ্যতে আপনি একক টিকিট একাধিক ব্যবহারকারী বা গোষ্ঠীর মালিকানা পেতে চান? এই নকশাটি কার্যকর করে না যে টিকিটটি কেবল একটি একক সত্তার মালিকানাধীন হতে হবে

  • আপনি প্রতিটি ব্যবহারকারীর জন্য একটি ডিফল্ট গোষ্ঠী তৈরি করতে পারেন এবং টিকিট কেবলমাত্র সত্য গ্রুপ বা ব্যবহারকারীর ডিফল্ট গ্রুপের মালিকানাধীন থাকতে পারে।

  • অথবা (আমার পছন্দ) এমন একটি সত্তা মডেল করুন যা ব্যবহারকারী এবং গোষ্ঠী উভয়ের জন্যই বেস হিসাবে কাজ করে এবং সেই সত্তার মালিকানাধীন টিকিট রয়েছে।

আপনার পোস্ট করা স্কিমা ব্যবহার করে মোটামুটি উদাহরণ এখানে:

create table dbo.PartyType
(   
    PartyTypeId tinyint primary key,
    PartyTypeName varchar(10)
)

insert into dbo.PartyType
    values(1, 'User'), (2, 'Group');


create table dbo.Party
(
    PartyId int identity(1,1) primary key,
    PartyTypeId tinyint references dbo.PartyType(PartyTypeId),
    unique (PartyId, PartyTypeId)
)

CREATE TABLE dbo.[Group]
(
    ID int primary key,
    Name varchar(50) NOT NULL,
    PartyTypeId as cast(2 as tinyint) persisted,
    foreign key (ID, PartyTypeId) references Party(PartyId, PartyTypeID)
)  

CREATE TABLE dbo.[User]
(
    ID int primary key,
    Name varchar(50) NOT NULL,
    PartyTypeId as cast(1 as tinyint) persisted,
    foreign key (ID, PartyTypeId) references Party(PartyID, PartyTypeID)
)

CREATE TABLE dbo.Ticket
(
    ID int primary key,
    [Owner] int NOT NULL references dbo.Party(PartyId),
    [Subject] varchar(50) NULL
)

7
ব্যবহারকারীর / গ্রুপের টিকিটের জন্য একটি কোয়েরি কেমন হবে? ধন্যবাদ।
পলকন

4
গ্রুপ এবং ব্যবহারকারীর টেবিলগুলিতে স্থির গণিত কলামগুলির সুবিধা কী? পার্টি টেবিলের প্রাথমিক কীটি ইতিমধ্যে নিশ্চিত করে যে গ্রুপ আইডি এবং ব্যবহারকারীর আইডিতে কোনও ওভারল্যাপ থাকবে না, সুতরাং বিদেশী কীটি কেবলমাত্র পার্টিআইডিতে থাকা দরকার। লিখিত যে কোনও প্রশ্নের জন্য এখনও পার্টি টাইপনেম থেকে যেভাবেই সারণীগুলি জানতে হবে।
অ্যারিন টেলর

1
@ অরিনটায়লর স্থায়ী কলামটি আমাদেরকে ধরণের ব্যবহারকারী পার্টি তৈরি করতে এবং এটি ডিবিও.গ্রুপের একটি রেকর্ডের সাথে সম্পর্কিত থেকে বাধা দেয়।
নাথান Skerl

3
@ পলকন আমি জানি এটি একটি পুরানো প্রশ্ন তবে ক্যোয়ারীটি এমন কিছু হবে SELECT t.Subject AS ticketSubject, CASE WHEN u.Name IS NOT NULL THEN u.Name ELSE g.Name END AS ticketOwnerName FROM Ticket t INNER JOIN Party p ON t.Owner=p.PartyId LEFT OUTER JOIN User u ON u.ID=p.PartyId LEFT OUTER JOIN Group g on g.ID=p.PartyID;যার ফলস্বরূপ আপনার প্রতিটি টিকিটের বিষয় এবং মালিকের নাম থাকবে।
কোরি ম্যাকমাহন

2
বিকল্প 4 সম্পর্কে, কেউ নিশ্চিত করতে পারেন যে এটি কোনও অ্যান্টি প্যাটার্ন বা কোনও বিরোধী প্যাটার্নের সমাধান?
inckka

31

@ নাথান স্কারেলের তালিকার প্রথম বিকল্পটি হ'ল আমি একবার কাজ করেছি এমন একটি প্রকল্পে বাস্তবায়িত হয়েছিল, যেখানে তিনটি টেবিলের মধ্যে একই রকম সম্পর্ক স্থাপন করা হয়েছিল। (তাদের মধ্যে একটির সাথে অন্য দু'জনের উল্লেখ করা হয়েছে, একজন একবারে one

সুতরাং, রেফারেন্সিং টেবিলটিতে দুটি বিদেশী কী কলাম ছিল এবং এটির গ্যারান্টি দেওয়ার ক্ষেত্রেও সীমাবদ্ধতা ছিল যে ঠিক একটি টেবিল (উভয় নয়, নয়) একটিও সারি দ্বারা রেফারেন্স করা হয়েছিল।

আপনার টেবিলগুলিতে প্রয়োগ করার সময় এটি দেখতে কেমন হতে পারে তা এখানে:

CREATE TABLE dbo.[Group]
(
    ID int NOT NULL CONSTRAINT PK_Group PRIMARY KEY,
    Name varchar(50) NOT NULL
);

CREATE TABLE dbo.[User]
(
    ID int NOT NULL CONSTRAINT PK_User PRIMARY KEY,
    Name varchar(50) NOT NULL
);

CREATE TABLE dbo.Ticket
(
    ID int NOT NULL CONSTRAINT PK_Ticket PRIMARY KEY,
    OwnerGroup int NULL
      CONSTRAINT FK_Ticket_Group FOREIGN KEY REFERENCES dbo.[Group] (ID),
    OwnerUser int NULL
      CONSTRAINT FK_Ticket_User  FOREIGN KEY REFERENCES dbo.[User]  (ID),
    Subject varchar(50) NULL,
    CONSTRAINT CK_Ticket_GroupUser CHECK (
      CASE WHEN OwnerGroup IS NULL THEN 0 ELSE 1 END +
      CASE WHEN OwnerUser  IS NULL THEN 0 ELSE 1 END = 1
    )
);

আপনি দেখতে পাচ্ছেন, Ticketটেবিলের দুটি কলাম রয়েছে, OwnerGroupএবং OwnerUserউভয়ই হ'ল বিদেশী কীগুলি। (অন্যান্য দুটি টেবিলের স্বতন্ত্র কলামগুলি সেই অনুযায়ী প্রাথমিক কী তৈরি করা হয়েছে CK_Ticket_GroupUsercheck ) চেক সীমাবদ্ধতাটি নিশ্চিত করে যে দুটি বিদেশী কী কলামগুলির মধ্যে একটিতে কেবল একটি রেফারেন্স রয়েছে (অপরটি ন্যূনাল, এজন্য উভয়ই নলাবদ্ধ থাকতে হবে)।

( Ticket.IDএই বিশেষ প্রয়োগের জন্য প্রাথমিক কীটি প্রয়োজনীয় নয় তবে এটি অবশ্যই টেবিলে রাখলে ক্ষতি হবে না))


1
আমাদের সফ্টওয়্যারটিতে এটি আমাদের কাছে রয়েছে এবং আপনি যদি জেনেরিক ডেটা অ্যাক্সেস ফ্রেমওয়ার্ক তৈরি করার চেষ্টা করছেন তবে আমি এড়াতে চাই। এই নকশাটি অ্যাপ স্তরটিতে জটিলতা বাড়বে।
ফ্র্যাঙ্ক.জার্মিন

4
আমি এসকিউএল-তে সত্যিই নতুন তাই যদি এটি ভুল হয় তবে আমাকে সংশোধন করুন, তবে আপনি যখন অত্যন্ত আত্মবিশ্বাসী হন যে আপনার কেবলমাত্র দুটি মালিকের টিকিটের প্রয়োজন হবে তখন এই নকশাটি ব্যবহার করার একটি পদ্ধতি বলে মনে হয়। রাস্তার নিচে যদি কোনও তৃতীয় টিকিটের মালিকের প্রকারটি চালু করা হয়, আপনাকে টেবিলে একটি তৃতীয় nullable বিদেশী কী কলামটি যুক্ত করতে হবে।
শাদোনিনিজা

@ শাদোনিঞ্জা: আপনি ভুল নন আসলে, আমি মনে করি এটি লাগানোর একটি সম্পূর্ণ সুষ্ঠু উপায়। আমি সাধারণত এই ধরণের সমাধানের সাথে ঠিক আছি যেখানে এটি ন্যায়সঙ্গত, তবে বিকল্পগুলির বিষয়ে বিবেচনা করার সময় এটি অবশ্যই আমার মনে প্রথম হবে না - আপনি যে কারণটি উল্লেখ করেছেন তার কারণেই।
অ্যান্ড্রি এম

2
@ ফ্রাঙ্ক.জার্মিন এক্ষেত্রে আপনি দুটি কলামের উপর ভিত্তি করে একটি অনন্য বিদেশী কী ব্যবহার করতে পারেন RefID, RefTypeযেখানে RefTypeলক্ষ্য সারণির একটি নির্দিষ্ট সনাক্তকারী। আপনার যদি সততার প্রয়োজন হয় তবে আপনি ট্রিগার বা অ্যাপ্লিকেশন স্তরে চেক করতে পারেন। এক্ষেত্রে জেনেরিক পুনরুদ্ধার সম্ভব। এসকিউএল এর দ্বারা এফকে সংজ্ঞাটি দেওয়া উচিত, যা আমাদের জীবন আরও সহজ করে তোলে।
ডিজেএমজে

2

তবুও আরেকটি বিকল্প হ'ল Ticket, একটি কলামের নিজস্ব সত্তার প্রকার ( Userবা Group) নির্দিষ্ট করে , দ্বিতীয় কলামটি রেফারেন্সড Userবা Groupআইডি সহ বিদেশী কীগুলি ব্যবহার না করে বরং পরিবর্তিত রেফারেন্সিয়াল অখণ্ডতা প্রয়োগের জন্য ট্রিগারের উপর নির্ভর করতে হবে।

নাথানের চমৎকার মডেলটির উপরে আমি এখানে দুটি সুবিধা দেখতে পাচ্ছি (উপরে):

  • আরও তাত্ক্ষণিক স্বচ্ছতা এবং সরলতা।
  • সহজ প্রশ্ন লিখতে।

1
কিন্তু এটি কি কোনও বিদেশী কী অধিকারের অনুমতি দেয় না? আমি এখনও আমার বর্তমান প্রকল্পের জন্য সঠিক নকশাটি বের করার চেষ্টা করছি, যেখানে একটি টেবিল ভবিষ্যতে কমপক্ষে 3 সম্ভবত আরও উল্লেখ করতে
পারে

2

আরেকটি পদ্ধতির মধ্যে এমন একটি অ্যাসোসিয়েশন টেবিল তৈরি করা হয় যাতে প্রতিটি সম্ভাব্য সংস্থানীয় সংস্থার জন্য কলাম থাকে। আপনার উদাহরণে, বিদ্যমান দুটি মালিকের প্রত্যেকের নিজস্ব নিজস্ব টেবিল রয়েছে (যার অর্থ আপনার কাছে উল্লেখ করার মতো কিছু আছে)। যদি সর্বদা এটি হয় তবে আপনার এর মতো কিছু থাকতে পারে:

CREATE TABLE dbo.Group
(
    ID int NOT NULL,
    Name varchar(50) NOT NULL
)  

CREATE TABLE dbo.User
(
    ID int NOT NULL,
    Name varchar(50) NOT NULL
)

CREATE TABLE dbo.Ticket
(
    ID int NOT NULL,
    Owner_ID int NOT NULL,
    Subject varchar(50) NULL
)

CREATE TABLE dbo.Owner
(
    ID int NOT NULL,
    User_ID int NULL,
    Group_ID int NULL,
    {{AdditionalEntity_ID}} int NOT NULL
)

এই সমাধানের সাহায্যে আপনি ডাটাবেসে নতুন সত্ত্বা যুক্ত করার সাথে সাথে নতুন কলামগুলি যুক্ত করতে থাকবেন এবং আপনি @ নাথন স্কারেলের দেখানো বিদেশী কী সীমাবদ্ধতা প্যাটার্নটি মুছবেন এবং পুনরায় তৈরি করবেন। এই সমাধানটি @ নাথন স্কারেলের সাথে খুব মিল তবে ভিন্ন দেখাচ্ছে (পছন্দ পর্যন্ত)।

যদি আপনি প্রতিটি নতুন মালিকের ধরণের জন্য একটি নতুন টেবিল না রাখেন তবে প্রতিটি সম্ভাব্য মালিকের জন্য বিদেশী কী কলামের পরিবর্তে একটি মালিক_প্রকার অন্তর্ভুক্ত করা ভাল হবে:

CREATE TABLE dbo.Group
(
    ID int NOT NULL,
    Name varchar(50) NOT NULL
)  

CREATE TABLE dbo.User
(
    ID int NOT NULL,
    Name varchar(50) NOT NULL
)

CREATE TABLE dbo.Ticket
(
    ID int NOT NULL,
    Owner_ID int NOT NULL,
    Owner_Type string NOT NULL, -- In our example, this would be "User" or "Group"
    Subject varchar(50) NULL
)

উপরের পদ্ধতিটি সহ আপনি যতগুলি মালিকানার প্রকারের পছন্দগুলি যোগ করতে পারেন Owner_ID এর কোনও বিদেশী কী বাধা থাকবে না তবে অন্য সারণির রেফারেন্স হিসাবে ব্যবহৃত হবে। ক্ষয়ক্ষতিটি হ'ল স্কীমার উপর ভিত্তি করে এটি মালিকানাধীন কী রয়েছে তা দেখার জন্য আপনাকে টেবিলটি দেখতে হবে। আমি কেবলমাত্র এটির পরামর্শ দিই যদি আপনি আগে থেকে মালিকের প্রকারগুলি জানেন না এবং তারা অন্য টেবিলের সাথে লিঙ্ক করবেন না। আপনি যদি আগে থেকে মালিকের প্রকারগুলি জানেন তবে আমি @ নাথন স্কারেলের মতো একটি সমাধান নিয়ে যাব।

দুঃখিত যদি আমার কিছু এসকিউএল ভুল হয় তবে আমি এটি একসাথে ছুঁড়ে ফেলেছি।


-4
CREATE TABLE dbo.OwnerType
(
    ID int NOT NULL,
    Name varchar(50) NULL
)

insert into OwnerType (Name) values ('User');
insert into OwnerType (Name) values ('Group');

আমি মনে করি এটি পতাকা ব্যবহারের পরিবর্তে আপনি যা চান তা উপস্থাপনের সবচেয়ে সাধারণ উপায়।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.