最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Milkman problem in SQL: how to create a linked list without losing FK relationships - Stack Overflow

programmeradmin3浏览0评论

I'm using the Milkman example to explain what I'm trying to achieve.

I have a main class, with a PK and a dozen of FKs. Let's call it a milkman. The FKs relate to the different "classes" that he's part of. For example, he is a person (ID details, gender, wtv), he has an employer (TaxId, Name, Location), he has a family (spouse, descendants), those descendants are persons.. You get the picture.

So I already have a scheme with a few tables with relations between them, all leading to my milkman table. So, the milkman, hence he's a milkman after all, will distribute its product through a said path. The path is composed by different establishments, they can be "houses" (1 type of class) or "companies" (another type of class) or ... - assume there are more possibilities. And houses and companies each have their ID (PK).

Each milkman has its path. So, Milkman1 will go to House1 first, then will go to House2, and then will finish his day in Company1, for example.

My C background asks me to do a linked list: each class will have a "Previous ID" and a "Next ID" field. And using that I can link stuff. But that stuff, isn't actually related to each other via FK. So if I draw a scheme of my database, both Houses and Companies are tables that have no relation with Milkman. They will not be attached to anything, really.

So, is there a way to go around this problem, creating relationships between the Milkman and his delivery locations?

If not, would it be possible to do it if we only had Houses and not Companies (only 1 class)?

I don't know if I'm missing something (my poor SQL knowledge hasn't been tested in a while), or if I'm too focused on creating relations PK-FK and there's no need for it, and I can work things out in another way (for example for DELETE CASCADE) on the C# programming layer.

I'm using the Milkman example to explain what I'm trying to achieve.

I have a main class, with a PK and a dozen of FKs. Let's call it a milkman. The FKs relate to the different "classes" that he's part of. For example, he is a person (ID details, gender, wtv), he has an employer (TaxId, Name, Location), he has a family (spouse, descendants), those descendants are persons.. You get the picture.

So I already have a scheme with a few tables with relations between them, all leading to my milkman table. So, the milkman, hence he's a milkman after all, will distribute its product through a said path. The path is composed by different establishments, they can be "houses" (1 type of class) or "companies" (another type of class) or ... - assume there are more possibilities. And houses and companies each have their ID (PK).

Each milkman has its path. So, Milkman1 will go to House1 first, then will go to House2, and then will finish his day in Company1, for example.

My C background asks me to do a linked list: each class will have a "Previous ID" and a "Next ID" field. And using that I can link stuff. But that stuff, isn't actually related to each other via FK. So if I draw a scheme of my database, both Houses and Companies are tables that have no relation with Milkman. They will not be attached to anything, really.

So, is there a way to go around this problem, creating relationships between the Milkman and his delivery locations?

If not, would it be possible to do it if we only had Houses and not Companies (only 1 class)?

I don't know if I'm missing something (my poor SQL knowledge hasn't been tested in a while), or if I'm too focused on creating relations PK-FK and there's no need for it, and I can work things out in another way (for example for DELETE CASCADE) on the C# programming layer.

Share Improve this question asked Jan 22 at 14:36 ATSlooking4thingsATSlooking4things 1452 silver badges10 bronze badges 9
  • 1 I would use a delivery table that has fkMilkman, fkEtablishment, sequence, and a DateTime stamp. – Bart McEndree Commented Jan 22 at 14:39
  • @BartMcEndree I assume you're suggesting adding a big enough table to fit the largest possible path, with as many columns for establishments as needed. But, fkEstablishment is an FK, so.. it cannot be nullable. Would you have a default establishmentID in all of them? and replace it with the respective establishmentID when you go through it? – ATSlooking4things Commented Jan 22 at 14:42
  • 1 No. each row is a stop. Delivery table has pkDelivery and a DeliveryGroup. Milk man might be assigned a delivery group in the morning and another delivery group in the afternoon. So 5 tables (Staff, Delivery, Establishment, EstablishmentType, DeliveryGroup). – Bart McEndree Commented Jan 22 at 14:46
  • @BartMcEndree I'm not sure I understand it. DeliveryGroup is where the sequence is? Staff has a Delivery, and follows a DeliveryGroup, through Establishments and each has its EstablishmentType? But what exactly is DeliveryGroup? What would be the columns? And, are the sequences pre-defined or will be added when they occur? What if I have 300 possible sequences? Wouldn't it be hard (computationally costly) to keep checking if the current sequence exists, and if not, to add it? – ATSlooking4things Commented Jan 22 at 15:28
  • 1 I made a fiddle that shows an example of the tables I suggested dbfiddle.uk/v3dANOdd – Bart McEndree Commented Jan 22 at 17:01
 |  Show 4 more comments

1 Answer 1

Reset to default 1

Here is a table structure you could use

https://dbfiddle.uk/70p8XwV_

Create Table EstablishmentType (
  pkEstablishmentType integer IDENTITY(1,1),
  TypeName varchar(512),
  created_at datetime DEFAULT (getdate()) 
);

INSERT INTO EstablishmentType (TypeName) VALUES 
  ('Residential'),
  ('Business'),
  ('Orphanage'),
  ('Hospital'),
  ('School'),
  ('Special');


SELECT * FROM EstablishmentType

Create Table DeliveryGroup(
  pkDeliveryGroup integer IDENTITY(1,1),
  GroupName varchar(512),
  Duration integer,
  Milage integer,
  FuelCost integer,
);

INSERT INTO EstablishmentType (TypeName) VALUES
('Residential Morning route'),
 ( 'Residential Afternoon route'),
 ( 'Business Morning route'),
 ( 'Business Afternoon route'),  
 ( 'Special Deliveries');

SELECT * FROM EstablishmentType

Create Table Staff (
  pkStaff integer IDENTITY(1,1), 
  Firstname varchar(512),
  Lastname varchar(512),
  Job varchar(512),
  DOB varchar(20),
  Sex varchar(20),
  Supervisor integer,
  created_at datetime DEFAULT (getdate()) 
);

INSERT INTO Staff (Firstname,Lastname,Job,DOB,Sex,supervisor) VALUES
('Amanda','Jones','Supervisor','1990-1-1','F',-1),
('John','Smith','DeliveryDriver','2000-1-1','M',1);

SELECT * FROM Staff


Create Table Establishment(
  pkEstablishment integer IDENTITY(1,1),
  fkEstablishmentType integer,
  Name varchar(512),
  Address varchar(512),
  created_at datetime DEFAULT (getdate()) 
);

INSERT INTO Establishment (fkEstablishmentType,Name,Address) VALUES
(1,'Mr Adams','123 South ave'),
(1,'Mr Carie','124 South ave'),
(1,'Ms Walls','126 South ave'),   
(2,'Express Resto','127 South ave'),   
(2,'Subway','128 South ave');     

SELECT * FROM Establishment

Create Table Delivery (
  pkDelivery integer IDENTITY(1,1), 
  fkDeliveryGroup integer,
  fkStaff integer,
  fkEstablishment integer,
  Sequence integer,
  comment varchar(512),  
  deliveryScheduled_at datetime,  
  deliveryCompleted_at datetime  
);

INSERT INTO Delivery (fkDeliveryGroup,fkStaff,fkEstablishment,Sequence) VALUES
  (1,1,1,1),
  (1,1,2,2),
  (1,1,3,3),
  (2,1,4,1),
  (2,1,5,2);

SELECT * FROM Delivery

SELECT *
FROM Delivery D
LEFT JOIN Establishment E ON E.pkEstablishment=D.fkEstablishment
LEFT JOIN EstablishmentType ET ON ET.pkEstablishmentType=E.fkEstablishmentType
LEFT JOIN Staff S ON S.pkStaff=D.fkStaff
LEFT JOIN DeliveryGroup DG on DG.pkDeliveryGroup=D.fkDeliveryGroup
发布评论

评论列表(0)

  1. 暂无评论