SQL column which is a list containing other rows - sql-server

I have a table which looks like this:
Persons
| Id | Name | FavoriteColor |
And I want to add a new column which is "Friends" so that it becomes
Persons
| Id | Name | FavoriteColor | Friends |
I want the Friends column to be (in abstraction) a list containing the Ids of other rows in the Persons table.
What's the best way to do this? I know I can use FK's to link up tables, but I'm not just linking a specific row to a specific row in a different table, but rather a specific row to a specific table.

You dont add a field, you create a second table
Persons: id, Name, Favorite Color
Friends: PersonA_id, PersonB_id
Where PersonA_id, PersonB_id are Foreign Key to Persons table.
So you can have things like this in persons
id Name Color
1 Luis Blue
2 Pedro Red
3 Ana Yellow
4 Donald Black
Friends:
PersonA_id PersonB_id
1 2
3 1
Luis have 2 friends, Pedro and Ana only have a friend (Luis), and Donald 0 friends.

Related

Single table column refers to multiple primary key

I need to store multiple values in a single column.
For example I am creating table which holds the user preferences
e.g.
| user_id | cities | countries |
|---------|------------|------------|
| 1 | 10, 11, 23 | 21, 34 |
because i can't store them as array (or don't prefer to store as array even if it is available - due to maintenance and performance reasons - and better RDMS design), i have to create a mapping table like this
| user_id | type | reference_id |
|---------|---------|--------------|
| 1 | CITY | 10 |
| 1 | CITY | 11 |
| 1 | CITY | 23 |
| 1 | COUNTRY | 21 |
| 1 | COUNTRY | 34 |
The reference id in this column refers to the master tables like city, country, etc.
The problem here i see is
I can't have FK reference to city or country table, because single reference_id column may refer to city or country depends on the type
As i can't have FK, there is no guaranty that we can't have dirty data
Is there any better approach?
Note:
I have given city/country as sample, but i need to have around 20 columns which can have multiple values like city or country
In future i may introduce some boolean preference like "whether you like to travel" so i might want to store TYPE as "TRAVEL" and referece_id as 0 for yes 1 for no; which definately will not have any reference
You could create a Location Table {LocationId, locationType (city/country)}
and then everytime you add a new record to the city or country table, add it to location table first, then add it to city (or country) table as appropriate with same cityId (or countryId) as was used as LocationId in Location Table.
then create FK between preferences table and location table, and add [zero or one] to one (0/1 - 1) FK relationship between City and country tables to the Location table. (Every record in City and COuntry table tables must be in Location table, but not the other way around.
You're saying you want a table for generic data instead of 20 lookup tables enforcing RI? On a large system, the data would be stored in multiple tables instead of using a delimiter to separate the values and then exploding them out in another table, introducing the problem of enforcing RI. If you're storing values that are really generic, like code/description pairs, you just need a codeSetID field to identify which codes belong in which codesets.

Modelling a cube in SSAS

I'm new to designing cubes with SSAS.
In my simple cube, I have one fact table with 3 dimension tables, as below. The fact table (table1) contains a list of client IDs and other columns linking to the 3 dimensions. This all works fine.
table1
client_id | dimension_link_1 | dimension_link_2 | dimension_link_3
AAAAA | xxx |zzz |bbb
BBBBB | yyy |aaa |ccc
I have another table (table2) that contains three columns - Client ID, Classification Type and Classification Name. A client may have 1-n classifications recorded against them (i.e. ethnicity, religion, allergies etc) so the Client ID may appear on multiple rows in table2. e.g.
table2
client_id | classification_type | classification_name
AAAAA | Ethnicity | Japanese
AAAAA | Allergy | Hayfever
AAAAA | Nationality | Russian
BBBBB | Ethnicity | Spanish
BBBBB | Allergy | Aspirin
BBBBB | Nationality | Spanish
BBBBB | Physical Support | Yes
I want to add table2 into my cube so that I can aggregate the list of client IDs by the existing fact table (table1) by Classification Type and Classification Name in table2.
However, I'm not sure what the correct approach for doing this is? I tried joining table2 to the fact table (table1) as a dimension linked on Client ID but I think this only joined the two objects together using the first occurrence of the Client ID in table2.
Help! :)
Thanks,
Hologram
Import table2 as both a fact table and a dimension. Then in the cube designer in the dimension usage tab, when specifying the relationship between the measure group formed from table1 and the dimension formed from table2, choose "Many to Many" as the relationship type and ensure the "intermediate measure group" is the one you formed from table2.

sqlite3 - making the combination of two entries unique

Table:
Car | Year | Colour
---------------
=
BMW | 2013 | Black
Benz | 2011 | Red
BMW | 2011 | Orange
As you can see, neither 'Car' nor 'Year' columns are unique. But how can I make the combination of Car and Make unique such that this table doesn't accept any other (BMW, 2013, whatever_colour) entries?
You can do either:
CREATE UNIQUE INDEX ON TableName(Car,Year)
or you can re-create the table with a PRIMARY KEY on (Car, Year). If you have other tables that identify models with the Car, Year combination and you want to ensure that those pairs are checked against the main table, the PRIMARY KEY is the preferred solution (with matching FOREIGN KEYs declared on the other table(s)).

One or four tables? (db structure)

Items are connected to:
one or more "region" and/or
one or more "county" and/or
one or more "city" and/or
one or more "place".
My question is how I should set up the relations:
id | thingID | regionId | countyId | cityId | placeId
or
4 tables?
id | thingId | regionId
id | thingId | countyId
id | thingId | cityId
id | thingId | placeId
or is there perhaps another better solution?
I may be overthinking this, but I think there's probably a relationship between "region", "county", "city" and "place" - an item that belongs to a "place" should also belong to the city, county and region.
You can solve this in both the designs you provide - but you need a fair amount of additional logic. In the first solution, you need to make sure that every time you insert a record, you populate the location from "left to right" - a record with only "place" is not valid.
In the second solution, you need to populate all relevant rows - an item in Chelsea must also have records for London, Middlesex and South East England.
There's another way...
Table: location
ID Name Parent
------------------------
1 South East England null
2 Middlesex 1
3 London 2
4 Chelsea 3
5 Kent 1
6 Canterbury 5
Table: item
Id name
-----------------
1 Posh Boy
2 Cricket ground
3 Rain
Table: item_location
ItemID LocationID
--------------------
1 4 //Posh boy in Chelsea
2 2 // Cricket ground in Middlesex
3 1 // Rain in the South East of England.
The second option is clearly better. It's a many-to-many relationship for each of these categories, and that's what the second option describes.
The first option would result in some very odd data. If you had a ThingId that was associated to all of the different types once, you would have one row that had all the columns filled in. Then if your ThingId needed to be tied to an additional city, you would have another row that had only the cityId filled in, with the other columns remaining null.
A table design that results in a lot of null values is usually (not always) a sign that your model is flawed.

DB Data migration

I have a database table called A and now i have create a new table called B and create some columns of A in table B.
Eg: Suppose following columns in tables
Table A // The one already exists
Id, Country Age Firstname, Middlename, Lastname
Table B // The new table I create
Id Firstname Middlename Lastname
Now the table A will be look like,
Table A // new table A after the modification
Id, Country, Age, Name
In this case it will map with table B..
So my problem is now i need to kind of maintain the reports which were generated before the table modifications and my friend told me you need to have a data migration..so may i know what is data migration and how its work please.
Thank you.
Update
I forgot to address the reporting issue raised by the OP (Thanks Mark Bannister). Here is a stab at how to deal with reporting.
In the beginning (before data migration) a report to generate the name, country and age of users would use the following SQL (more or less):
-- This query orders users by their Lastname
SELECT Lastname, Firstname, Age, Country FROM tableA order by Lastname;
The name related fields are no longer present in tableA post data migration. We will have to perform a join with tableB to get the information. The query now changes to:
SELECT b.Lastname, b.Firstname, a.Country, a.Age FROM tableA a, tableB b
WHERE a.name = b.id ORDER BY b.Lastname;
I don't know how exactly you generate your report but this is the essence of the changes you will have to make to get your reports working again.
Original Answer
Consider the situation when you had only one table (table A). A couple of rows in the table would look like this:
# Picture 1
# Table A
------------------------------------------------------
Id | Country | Age | Firstname | Middlename | Lastname
1 | US | 45 | John | Fuller | Doe
2 | UK | 32 | Jane | Margaret | Smith
After you add the second table (table B) the name related fields are moved from table A to table B. Table A will have a foreign key pointing to the table B corresponding to each row.
# Picture 2
# Table A
------------------------------------------------------
Id | Country | Age | Name
1 | US | 45 | 10
2 | UK | 32 | 11
# Table B
------------------------------------------------------
Id | Firstname | Middlename | Lastname
10 | John | Fuller | Doe
11 | Jane | Margaret | Smit
This is the final picture. The catch is that the data will not move from table A to table B on its own. Alas human intervention is required to accomplish this. If I were the said human I would follow the steps given below:
Create table B with columns Id, Firstname, Middlename and Lastname. You now have two tables A and B. A has all the existing data, B is empty .
Add a foreign key to table A. This FK will be called name and will reference the id field of table B.
For each row in table A create a new row in table B using the Firstname, Middlename and Lastname fields taken from table A.
After copying each row, update the name field of table A with the id of the newly created row in table B.
The database now looks like this:
# Table A
-------------------------------------------------------------
Id | Country | Age | Firstname | Middlename | Lastname | Name
1 | US | 45 | John | Fuller | Doe | 10
2 | UK | 32 | Jane | Margaret | Smith | 11
# Table B
------------------------------------------------------
Id | Firstname | Middlename | Lastname
10 | John | Fuller | Doe
11 | Jane | Margaret | Smith
Now you no longer need the Firstname, Middlename and Lastname columns in table A so you can drop them.
voilĂ , you have performed a data migration!
The process I just described above is but a specific example of a data migration. You can accomplish it in a number of ways using a number of languages/tools. The choice of mechanism will vary from case to case.
Maintenance of the existing reports will depend on the tools used to write / generate those reports. In general:
Identify the existing reports that used table A. (Possibly by searching for files that have the name of table A inside them - however, if table A has a name [eg. Username] which is commonly used elsewhere in the system, this could return a lot of false positives.)
Identify which of those reports used the columns that have been removed from table A.
Amend the existing reports to return the moved columns from table B instead of table A.
A quick way to achieve this is to create a database view that mimics the old structure of table A, and amend the affected reports to use the database view instead of table A. However, this adds an extra layer of complexity into maintaining the reports (since developers may need to maintain the database view as well as the reports) and may be deprecated or even blocked by the DBAs - consequently, I would only recommend using this approach if a lot of existing reports are affected.

Resources