Database structures - populating tables via foreign keys and summation - sql

Good afternoon,
I've been trying to brainstorm ways to do this, but I've been unable to think of something solid so far. As a last resort I've decided to ask the brilliant minds on stack overflow on some advice as to how I should do this. Some preface before I get started, I'm using SMSS 18 and Microsoft SQL Server 2017.
First of all, I'll show you the backbone database that I want to achieve with this:
Should I structure the database another way to achieve what I want to achieve? (A way to log meals with a summation of all the calories, etc.)
Is it possible to use foreign keys to populate a column in a foreign table? E.g. using X as primary key, populating Z column(in another table) with Y as a foreign key
How do I go about with wrapping this up and using SMSS to create the foreign keys to automatically do this?
Is it possible to do summation in MSSQL? I wanted to get the sum of calories in the final meal table so that I can later use that data in tableau to draw comparisons and create representations of that data. Should I let tableau do that or is it possible to do so with MSSQL?
I'm all over the place right now, I know my questions seem daunting, but I'm happy to provide much more information if you're missing anything.
I've got the flow of data planned and designed - but I do not know how exactly to implement this architecture in MSSQL.
Thank you in advance.

Well, I guess this is not really an answer to your question...
I would expect some data model like this:
ingredient (ingredient_id, ingredient_name, calories, fat, ...)
meal (meal_id, meal_name)
meal_ingredient (meal_id, ingredient_id, amount)
Per meal you would then calculate:
select mi.meal_id, sum(i.calories * mi.amount), sum(i.fat * mi.amount)
from ingredient
join meal_ingredient mi on mi.ingredient_id = i.ingredient_id
group by mi.meal_id;
For persons eating the meals:
person (person_id, name)
person_meal (person_id, meal_id, consume_date, consume_amount)
And a query for the persons' daily consumption:
select
pm.person_id, pm.consume_date,
sum(i.calories * mi.amount * pm.consume_amount),
sum(i.fat * mi.amount * pm.consume_amount)
from ingredient
join meal_ingredient mi on mi.ingredient_id = i.ingredient_id
join person_meal pm on pm.meal_id, mi.meal_id
group by pm.person_id, pm.consume_date
order by pm.person_id, pm.consume_date;
We would not store results reduantly, as we can always write queries to get them from the tables. After all, this is what SQL is about.

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.

Using a lookup table will result in many foreign keys

I am looking for more educated opinions on how best to use a lookup table in a SQL Server database.
The rough explanation is that I have a Results table in which ratings are assigned to a number of fields. Then I have a lookup table for these ratings like this:
RatingCode RatingName
1 Poor
2 OK
3 Satisfactory
etc.
The results table has about 50 columns which will contain a rating code.
Should each of these 50 columns be a foreign key? Is this way too many foreign keys and will it hinder performance? Are there any other ways I can achieve this?
This unfortunately sounds like a poorly designed table.
Just to clarify, you have a table defined like this:
CREATE TABLE SomeTable
(KeyColumn, ThingWithRatingCode1, ThingWithRatingCode2 ..., ThingWithRatingCode50)
This is an example of a denormalised table. This would be much better structured as a normalised table:
CREATE TABLE SomeTable
(KeyColumn, ThingToBeRated, RatingCode)
Rather than one record with 50 columns, you would have 50 records per KeyColumn. Therefore you only have the one foreign key (from the RatingCode column in SomeTable to your lookup table).
For further explanations of this just Google "3rd normal form" or "normalisation". I would suggest normalisation is almost always a minimum best practice when designing databases and tables.
Let me know if you have any further questions.
Regards,
Ash

SQL - Complex query using foreign keys

So, I am totally new to SQL, but the book I have from the courses I take is useless and I am trying to do a project for said course. Internet did not help me all that much (I do not know where to start exactly), so I want to ask for both links to good tutorials to check out as well as help with a very specific piece of query.
If anything I say is not clear enough, please ask me to explain! :)
Suppose two tables sale and p_sale in a database called jewel_store.
sale contains two columns: sale_CODE and sale_date
p_sale contains sale_CODE which references the above sale_ID, p_ID, p_sl_quantity and
p_sl_value
sale_CODE is the primary key of sale and sale_CODE,p_ID is the primary key of p_sale
For the time being p_ID is not of much use so just ignore it for the most part.
p_sl_quantityis int and p_sl_value is double(8,2). The first one is the quantity of the product bought and the second one is the value PER UNIT of the product.
As it probably is obvious a sale_CODE can be linked to a multitude of entries in the p_sale table (example for sale_CODE 1, I have 2 entries on p_sale).
All this is based on what I was given from the task and is correctly implemented and has some example values in.
What I now have to do is find the total income from sales in a specific month. My initial approach was to start structuring everything step by step so I have come to a point that looks like the follows:
SELECT
SUM(p_sl_value * p_sl_quantity) AS sales_monthly_income,
p_sale.sale_CODE
FROM jewel_store.p_sale
GROUP BY p_sale.sale_CODE
This is probably half way through as I can get the total money a sale generated for the store. So my next step was to use this query and SELECT from it. I messed it up a couple of times already and I am scratching my head now. What I did was like this:
SELECT
SUM(sales_monthly_income),
sales_monthly_income,
EXTRACT(MONTH FROM jewel_store.sale.sale_date) AS sales_month
FROM (
SELECT
SUM(p_sl_value * p_sl_quantity) AS sales_monthly_income,
sale_CODE
FROM jewel_store.p_sale
GROUP BY sale_CODE
) as code_income, jewel_store.sale
GROUP BY sales_month
First off, I only need to print the total_montly_income and the month columns in my final form, but I used this to clarify that everything went wrong in there. I think I need to somehow use the foreign key that references the other table, but my book is totally useless in helping me out. I would like someone to explain why this is wrong and what the right one would be and please point me to a good pdf, site or anything to learn how to do this kind of stuff. (I have checked W3SCHOOLS, it is good for the basics, but not for too advanced stuff)
Thanks in advance!
From the top of my head this could be it, group by month the sum of value times quantity.
SELECT
SUM(p.p_sl_value * p.p_sl_quantity) AS sales_monthly_income,
month(s.sale_date)
FROM p_sale p
inner join sale s on s.sale_code = p.sale_code
GROUP BY MONTH(s.sale_date)

How to use SQL Server views with distinct clause to Link to a detail table?

I may be total standard here, but I have a table with duplicate values across the records i.e. People and HairColour. What I need to do is create another table which contains all the distinct HairColour values in the Group of Person records.
i.e.
Name HairColour
--------------------
Sam Ginger
Julie Brown
Peter Brown
Caroline Blond
Andrew Blond
My Person feature view needs to list out the distinct HairColours:
HairColour Ginger
HairColour Brown
HairColour Blond
Against each of these Person feature rows I record the Recommended Products.
It is a bit weird from a Relational perspective, but there are reasons. I could build up the Person Feature"View as I add Person records using say an INSTEAD OF INSERT trigger on the View. But it gets messy. An alternative is just to have Person Feature as a View based on a SELECT DISTINCT of the Person table and then link Recommended Products to this. But I have no Primary Key on the Person Feature View since it is a SELECT DISTINCT View. I will not be updating this View. Also one would need to think about how to deal with the Person Recommendation records when a Person Feature record disappeared since since it is not based on a physical table.
Any thoughts on this please?
Edit
I have a table of People with duplicate values for HairColour across a number of records, e.g., more than one person has blond hair. I need to create a table or view that represents a distinct list of "HairColour" records as above. Against each of these "HairColour" records I need link another table called Product Recommendation. The main issue to start with is creating this distinct list of records. Should it be a table or could it be a View based on a SELECT DISTINCT query?
So Person >- HairColour (distinct Table or Distinct View) -< Product Recommendation.
If HairColour needs to be a table then I need to make sure it has the correct records in it every time a Person record is added. Obviously using a View would do this automatically, but I am unsure whether you can can hang another table off a View.
If I understand correctly, you need a table with a primary key that lists the distinct hair colors that are found in a different table.
CREATE TABLE Haircolour(
ID INT IDENTITY(1,1) NOT NULL,
Colour VARCHAR(50) NULL
CONSTRAINT [PK_Haircolour] PRIMARY KEY CLUSTERED (ID ASC))
Then insert your records. If this is querying a table called "Person" it will look like this:
INSERT INTO Haircolour (Colour) SELECT DISTINCT HairColour FROM Person
Does this do what you are looking for?
UPDATE:
Your most recent Edit shows that you are looking for a many-to-many relationship between the Person and ProductRecommendation tables, with the HairColour table functioning as a cross reference table.
As ErikE points out, this is a good opportunity to normalize your data.
Create the HairColour table as described above.
Populate it from whatever source you like, for example the insert statement above.
Modify both the Person and the ProductRecommendation tables to include a HairColourID field, which is an integer foreign key that points to the PK field of the HairColour table.
Update Person.HairColourID to point to the color mentioned in the Person.HairColour column.
Drop the Person.HairColour column.
This involves giving up the ability to put free form new color names into the Person table. Any new colors must now be added to the HairColour table; those are the only colors that are available.
The foreign key constraint enforces the list of available colors. This is a good thing. Referential integrity keeps your data clean and prevents a lot of unexpected errors.
You can now confidently build your ProductRecommendation table on a data structure that will carry some weight.
Are you simply looking for a View of distinct hair colors?
CREATE VIEW YourViewName AS
SELECT DISTINCT HairColour
FROM YourTableName
You can query this view like a table:
SELECT 'HairColour: ' + HairColour
FROM YourViewName
If you are trying to create a new (temp) table, the syntax would look like:
SELECT Name, HairColour
INTO #Temp
FROM YourTableName
GROUP BY Name, HairColour
Here the GROUP BY is doing the same work that a DISTINCT keyword would do in the select list. This will create a temp table with unique combinations of "Name" and "HairColour".
You need to clear up a few things in your post (or in your mind) first:
1) What are the objectives? Forget about tables and views and whatever. Phrase your objectives as an ordinary person would. For example, from what I could gather from your post:
"My objective is to have a list of recommended products based on each person's hair colour."
2) Once you have that, check what data you have. I assume you have a "Persons" table, with the columns "Name" and "HairColour". You check your data and ask yourself: "Do I need any more data to reach my objective?" Based on your post I say yes: you also need a "matching" between hair colours and product ids. This must be provided, or programmed by you. There is no automatic method of saying for example "brown means products X,Y,Z.
3) After you have all the needed data, you can ask: Can I perform a query that will return a close approximation of my objective?
See for example this fiddle:
http://sqlfiddle.com/#!2/fda0d6/1
I have also defined your "Select distinct" view, but I fail to see where it will be used. Your objectives (as defined in your post) do not make this clear. If you provide a thorough list in Recommended_Products_HairColour you do not need a distinct view. The JOIN operation takes care of your "missing colors" (namely "Green" in my example)
4) When you have the query, you can follow up with: Do I need it in a different format? Is this a job for the query or the application? etc. But that's a different question I think.

Ways to join and update tables in SQL

So I am a first time user here, and still relatively new to SQL. I am attempting to take 2 tables, and join them in a sense.
In Table1 I have the data:
House_Key ---Other Fields--- Customer_ID
House_Key is not unique, and as such I can have multiple Customer_IDs per household. House_Key is a numerical code, and Customer_ID is either Home, Business, or Bulk.
In Table2 I have the House_Key field, but not the Customer_ID field.
My goal is to have a new table that holds the fields of Table2 with a field called Customer_ID, but instead of having a new row for each type of Customer_ID like in Table 1, I want to have each House_Key only have one row, and the Customer_ID say something like "Home Business Bulk" if it is all three or any combination of them, but would prefer that it always have Home before Business before Bulk in the field.
Is there any way to do this? Thank you very much ahead of time.
Also, not sure if it matters, but in case it does I'm using SQL Server 2005.
Wow, I'm glad that you came here for an answer, but seems that you really need some reading about relational databases.
Instead of writing looong answer here're the links:
http://en.wikipedia.org/wiki/Database_normalization
http://en.wikipedia.org/wiki/Join_(SQL)