Table with set of 3 columns maximum which have same meaning - sql

I have table Person which have maximum 3 opinion and for each rows of Person we have different opinion, in other word you never find 2 person that have the same opinion, there is no many-to-many relationship between person and opinion.
I will never check opinion for validation like no 2 person have same opinion, it's just for information.
the question it is :
should i make just one table
Person ( #id_person , ... , opinion1 , opinion2 , opinion3 , ... )
or add a new table :
Person ( #id_person , ... )
opinions ( #id_opinion , opinion , *id_person* ) // id_person FK
For me i don't want to create a new table opinions because it will have no meaning i will always add a new rows as much i have a new Person
also if i group them in one table and i have just one opinion there will be problem of waste of space ? even if i declare opinion as varchar ?
And if i create a new table opinions it will need a primary pseudo-key id_opinion ?
a opinion can be a varchar(50).

I would recommend two tables. The first table is the persons table. This would have a PersonId and all sorts of other information about the person.
The second table would be the PersonOpinions table. This would have one row per opinion, with information such as:
PersonId
Opinion
Date and time of the opinion
Topic of the opinion (if appropriate)
Method for inputing the opinion (if appropriate)
From what you say, there is no need for a separate opinions table, because the opinion is basically "unique". However, you probably do want to store the opinions themselves in a separate table, which a separate row per opinion.
You can use a trigger to enforce the constraint that a person only has three opinions. If you decide to change this in the future, then it will be easy with a two-table solution.

I would suggest to go for 3 different tables(2 base and 1 intersection). Since Person and Opinions are 2 different entities and they might share a relationship of M:M so hence the need of intersection table. I believe it will simply things instead of clutering the info in 1 single table.

You should have two tables. (Whether you want opinion ids is a separate issue. You wouldn't need to.)
// person [id_person] has name [name] and ...
person(id_person,name,...)
// person [id_person] has opinion [opinion]
opinion(id_person,opinion)
fk (id_person) references person
Your design is bad partly because: it is not clear what the answers to the following questions are, yet the answers must be known for someone to use the database. When you have given the answers (ie the rest of a full design of your table) they will illustrate other problems.
Suppose:
person p1 has opinion o11.
person p1 has opinion o12.
person p1 has no other opinions.
person p3 has opinion o21
person p3 has no other opinions.
A. What row(s) go in the table?
B. What are queries (without knowing the table value) for rows where
person p has opinion [opinion]
person [person] does not have opinion o
C. Every table needs a statement parameterized by its columns where the rows in the table are the rows that make the statement true.
What is the statement for your table?
Why isn't it
person [id_person] is named [name] and ...
AND person [id_person] holds opinion [opinion1]
AND person [id_person] holds opinion [opinion2]
AND person [id_person] holds opinion [opinion3]
...
You should experience the further badness in answering the questions. Besides being unclear, the desription so far is also bad because the answers are ugly and your table is difficult to use. So much so that I don't even want to type examples of what I know they will be like. So I will leave the questions rhetorical rather than with examples until you give more info.

Related

How to understand this query?

SELECT DISTINCT
...
...
...
FROM Reviews Rev
INNER JOIN Reviews SubRev ON Subrev.W_ID=Rev.ID
WHERE Rev.Status='Approved'
This is a small part of a long query that I've been trying to understand for a day now. What is happening with the join? Reviews table appears to be joined with itself, under different aliases. Why is this done? What does it achieve? Also, ID field of the Reviews table is null for the entries that are nevertheless selected and returned. This is correct, but I don't understand how that can happen if the W_ID field is not null.
It allows you to join one row from the table to a different row in the table.
I've both seen this done, and used it myself, in cases where you maybe have a relationship between those rows.
Real-world examples:
An old version of a record and a newer version
Some sort of hierarchical relationship (e.g. if the table contains records of people, you can record that someone is a parent of someone else). There are probably plenty of other possible use cases, too.
SQL allows you to create a foreign key which relates between two different columns in the same table.

Matching Entities - Self many to many

Working with a new master data management product, specifically people matching.
I have two tables: Person and PersonMatch. PersonMatch is a join table that matches rows from Person to another row in Person.
Person: 1,2,3,4 (Per the PersonMatch, these are all the same Person).
PersonMatch: 1+2, 2+3, 3+4, 4+1
I can't wrap my head around a query to treat all four entities from the Person table as the same. Thanks for any help!
It sounds to me like you need a specific column that is a PersonUniqueId, and all the Person instances that are the same could have there own unique id to identify their differences, but they would each share the same 'PersonUniqueId', which reflects that they are really the same person, just with different or additional subsequent info.
If you do not go with a PersonUniqueId then you would need to figure out what in each record identifies the two persons as being the same, perhaps the name, or whatever else. Without knowing more about your overall structure It is hard to say what is the best direction, but hopefully this is a start.
It might be that the PersonMatch table is not even needed. Alternately, you could put the PersonUniqueId column in that table and then do something like:
SELECT p.*
FROM Persons p, PersonMatch pm
WHERE p.PersonId = pm.PersonId
GROUP BY pm.PersonUniqueId
Hope this helps.

Preserve old record values in relational DB

What is the best approach for the following situation?
Assume, that we have the following tables:
Companies:
COMPANY_ID
COMPANY_NAME
People:
PERSON_ID
PERSON_NAME
FK_COMPANY_ID
Meetings:
MEETING_ID
MEETING_NAME
MEETING_DATE
FK1_PERSON_ID
FK2_PERSON_ID
We have the following data:
/* Companies */
1, Company #1
2, Company #2
3, Company #3
/* People */
1, Vasya Pupkin, 1
2, Petya Vasechkin, 2
/* Meetings */
1, Meeting #1, 2014-02-01, 1, 2
Now, imagine that the person from Company #1 changes his company to Company #3. This will be of course reflected in the meetings view due to relation through person. And therefore, in the view form of the meeting it will show incorrect data in terms of the past situation (when a person was working in another company).
So, my question is how to preserve the view data for the meeting that has already past?
Currently I see the following solution. Extend the Meetings table as follows:
MEETING_ID
MEETING_NAME
MEETING_DATE
FK1_PERSON_ID
FK2_PERSON_ID
FK1_COMPANY_ID
COMPANY_NAME_1
FK2_COMPANY_ID
COMPANY_NAME_2
So that for historical purposes it will be possible to select the company_name_1 and company_name_2 rather than check actual person's company. And however, this would work even faster than relation, at the same time this moves me away from relational DB, and as this has to be used not just in one place, but in many places of a big project, it turns out that I will have a lot of data duplication.
Therefore, are there any better solutions for this problem?
UPDATE:
I see one possible solution in terms of relational DB. We need to introduce a new table:
Employments:
EMPLOYMENT_ID
FK_PERSON_ID
FK_COMPANY_ID
EMPLOYMENT_DATE
Assuming that a person can work only in a one company at the same time, we can know for sure, which company he worked in during the meeting. However, a small issue still exists: the company name (if renamed) will be the last one used. This can be fixed by the similar approach (if needed):
Company_Names:
FK_COMPANY_ID
COMPANY_NAME
ACTUAL_FROM_DATE
Seems that it adds some complexity but flexibility at the same time.
This is a standard problem that one encounters in real world databases. Your solution looks good. Keep in mind now, that to find out where some works you will need to do something like:
select * from employment where person_id=123 and
employment_date=(select max(employment_date)
from employment where person_id = 123)
That might be OK, but there are other solutions. For example, you can add a last_known column to employment and then your query for finding where a person works can now be:
select * from employment where person_id=123 and
last_known=1
There is a question https://stackoverflow.com/a/19144370/4350148 that may also be helpful.

MS SQL share identity seed amongst tables

In MS SQL is it possible to share an identity seed across tables? For example I may have 2 tables:
Table: PeopleA
id
name
Table: PeopleB
id
name
I'd like for PeopleA.id and PeopleB.id to always have unique values between themselves. I.e. I want them to share the same Identity seed.
Note: I do not want to hear about table partitioning please, only about if it's possible to share a seed across tables.
Original answer
No you can't and if you want to do this, your design is almost
certainly flawed.
When I wrote this in 2010 that was true. However, at this point in time SQL Server now has Sequences that can do what the OP wants to do. While this may not help the OP (who surely has long since solved his problem), it may help some one else looking to do the same thing. I do still think that wanting to do this is usually a sign of a design flaw but it is possible out of the box now.
No, but I guess you could create an IDENTITY(1, 2) on the one table and an IDENTITY(2, 2) on the other. It's not a very robust design though.
Could you instead refer to your entities as 'A1', 'A2', ... if they come from TableA and 'B1', 'B2', etc... if they come from TableB? Then it's impossible to get duplicates. Obviously you don't actually need to store the A and the B in the database as it is implied.
Not sure what your design is, but sometimes it is useful to use an inheritance-type model, where you have a base table and then sub-tables with substantially different attributes, e.g.:
Person
------
PersonID <-- PK, autoincrement
FirstName
LastName
Address1
...
Employee
--------
PersonID <-- PK (not autoincrement), FK to Person
JobRoleID
StartDate
Photo
...
Associate
---------
PersonID <-- PK (not autoincrement), FK to Person
AssociateBranchID
EngagementTypeID
...
In this case you would insert the base values to Person, and then use the resulting PersonID to insert into either Employee or Associate table.
If you really need this, create a third table PeopleMaster, where the identity(1,1) exists, make the two other tables just have int FKs to this identity value. Insert into the PeopleMaster and then into PeopleA or PeopleB.
I would really consider this a bad design though. Create one table with a PeopleType flag ("A" or "B") and include all common columns, and create child tables if necessary (for any different columns between the PeopleA and PeopleB)
No.
But I have worked on projects where a similar concept was used. In my case what we did was have a table called [MasterIdentity] which had one column [Id] (an identity seed). No other table in the database had any columns with an identity seed and when Identities were required a function/stored proc was called to insert a value into the [MasterIdentity] table and return the seed.
No, there is nothing built into SQL Server to do this.
Obviously there are workarounds such as both using an FK relationship to a table which does have a single IDENTITY and having some fancy constraints or triggers.

Is using Null to represent a Value Bad Practice?

If I use null as a representation of everything in a database table is that bad practice ?
i.e.
I have the tables: myTable(ID) and myRelatedTable(ID,myTableID)
myRelatedTable.myTableID is a FK of myTable.ID
What I want to accomplish is: if myRelatedTable.myTableID is null then my business logic will interpret that as being linked to all myTable rows.
The reason I want to do this is because I have an uknown amount of rows that could be inserted into myTable after the myRelatedTable row is created and some rows in the myRelatedTable need to reference all existing rows in myTable.
I think you might agree that it would be bad to use the number 3 to represent a value other an 3.
By the same reasoning it is therefore a bad idea to use NULL to represent anything other than the absence of a value.
If you disagree and twist NULL to some other purpose, the maintenance programmers that come after you will not be grateful.
Not a good idea, because then you cannot use the "related to all entries" fact in SQL queries at all. At some point, you'll probably want/need to do this.
Ideally there should be no nulls at all. There should be another table to represent the relation.
If you are going to assign special meanings however NULL should only ever mean "not assigned" - ie no relationship exists, use negative numbers, ie -1 if you want to trigger some business layer trickery. It should be obvious to any developers that come across this in the future that -1 is an extraordinary value that should not be treated as normal.
I don't think NULL is the best way to do it but you might use a separate tinyInt column to indicate that the row in MyRelatedTable is related to everything in MyTable, e.g. MyRelatedTable.RelatedAll. That would make it more explicit for other that have to maintain it. Then you could do some sort of Union query e.g.
SELECT M.ID, R.ID AS RelatedTableID,....
FROM MyTable M INNER JOIN MyRelated Table R ON R.myTableId = M.Id
UNION
SELECT M.ID, R.ID AS RelatedTableID,....
FROM MyTable M, MyRelatedTable R
WHERE R.RelatedAll = 1
Yes, for the simple reason that NULL represents no value. Not a special value; not a blank value, but nothing.
If the foreign key is just a simple integer, and it's generated automatically, then you could use 0 to represent the "magic" value.
What you posted, namely that a NULL in a foreign key asserts a relationship with all the rows in the referenced table, is very non standard. Off the top of my head, I think it's fraught with dangers.
What most people who use NULLs in FKs mean by it is that it asserts a relationship to NONE of the rows in the referenced table. This is common in the case of optional relationships, ones that can occur zero times.
Example: We have an HR database, with a table called "EMPLOYEES". We have two columns, called "EmpID" and "SupervisorID". (Many people call the first column simply "ID"). Every employee in the table has an entry under SupervisorID with the sole exception of the CEO of the company. THe CEO has a NULL in the SupervisorID column, meaning that the CEO has no supervisor. The CEO is accountable to the BOD, but that isn't represented in SupervisorID.
What you might mean by a relationship with ALL the rows in the refernced table is this: There's a POSSIBLE relationship between the row in question and ANY ONE of the rows in the reference table. When you start to get into the questions of the facts that are true in the real world but unknown to the database you open a whole big can of worms.