Logging for multiple tables - sql

Lets say we have a client table for sports brands like nike and adidas.
+--------------+------------+
| Client Table | |
+--------------+------------+
| Id | ClientName |
| 1 | Nike |
| 2 | Adidas |
+--------------+------------+
We also record customer information and their preferred sport and fitness level. Sports and fitness level are used in dropdown lists.
+--------------+------------+
| Sports Table | |
+--------------+------------+
| Id | Name |
| 1 | Basketball |
| 2 | Volleyball |
+--------------+------------+
+------------------+---------------+
| Fitnesslvl Table | |
+------------------+---------------+
| Id | Fitness Level |
| 1 | Beginner |
| 2 | Intermediate |
| 3 | Advance |
+------------------+---------------+
+----------------+--------------+----------+----------------+
| Customer Table | | | |
+----------------+--------------+----------+----------------+
| Id | CustomerName | SportsId | FitnessLevelId |
| 1 | John | 1 | 1 |
| 2 | Doe | 2 | 3 |
+----------------+--------------+----------+----------------+
Then sports brands want to filter our customer via sports and fitness level. In this example nike wants all sports while adidas only wants customer interested in basketball. Likewise, nike wants customer in all fitness level while adidas only wants advanced fitness level.
+---------------+----------+----------+
| Sports Filter | | |
+---------------+----------+----------+
| Id | ClientId | SportsId |
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 1 |
+---------------+----------+----------+
+-------------------+----------+--------------+
| Fitnesslvl Filter | | |
+-------------------+----------+--------------+
| Id | ClientId | FitnessLvlId |
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 3 |
| 4 | 2 | 3 |
+-------------------+----------+--------------+
How can we handle logging in this case when we want to record failed filters for the sports and fitness level? I'm thinking of two options
Create different table for each failed filter.
-Sports Failed Filter
-FitnessLevel Failed Filter
+----------------------+-------------+----------------+
| Sports Failed Filter | | |
+----------------------+-------------+----------------+
| Id | CustomerId | SportsFilterId |
| 1 | 1 | 2 |
| 2 | 1 | 3 |
+----------------------+-------------+----------------+
However if we have 10 filters, this means we will also have 10 failed filters table. I think this is very difficult to maintain.
Instead of different table for dropdown values like sports and fitness level, we can create lookup table, and a single failedfilter table.
I think the tradeoff is its not simple and there is no strict referential integrity.
Please let me know if you have different solution for this.
EDIT:
This filters are used in a backend application and the filtering logic is there. I dont plan to include this logic in the database as the query will be very complex and hard to maintain.

Related

Designing a database for a workout tracker

I'm designing a database for a workout tracker app. Each user should be able to track multiple workouts (routines). A workout can have multiple exercises an exercise can be used in many workouts. Each exercise will have a specific track type (weight and reps, distance and time, only reps).
My tables so far:
| User | |
|------|-------|
| id | name |
| 1 | Ilka |
| 2 | James |
| Exercise | | |
|----------|---------------------|---------------|
| id | name | track_type_id |
| 1 | Barbell Bench Press | 1 |
| 2 | Squats | 1 |
| 3 | Deadlifts | 1 |
| 4 | Rowing Machine | 3 |
| Workout | | |
|---------|---------|-----------------|
| id | user_id | name |
| 1 | 1 | Chest & Triceps |
| 2 | 1 | Legs |
| Workout_Exerice (Junction table) | |
|-----------------|------------------|------------|
| id | exersice_id | workout_id |
| 1 | 1 | 1 |
| 2 | 2 | 1 |
| 3 | 4 | 1 |
| Workout_Sets | | | |
|--------------|---------------------|------|--------|
| id | workout_exersice_id | reps | weight |
| 1 | 1 | 12 | 120 |
| 2 | 1 | 10 | 120 |
| 3 | 1 | 8 | 120 |
| 4 | 2 | 10 | 220 |
| 5 | 3 | null | null |
| TrackType | |
|-----------|-----------------|
| id | name |
| 1 | Weight and Reps |
| 2 | Reps Only |
| 3 | Distance Time |
My issue is how to incorporate the TrackType table for each workout set, my first option was to create columns in the Workout_Sets table for each tracking type (weight and reps, distance and time, only reps) but that means for many rows I will have many nulls. Another option I thought was to use an EAV type table but I'm not sure. Also do you think my design is efficient (Over-normalization)?
I would say that the most efficient way is to have nulls in your table. The alternative would require you to split many of the category's into separate tables. Also a recommendation is that you start factoring a User ID table into your database
Your description states that “Each exercise will have a specific track type” suggesting a one-to-one relationship between Exercise and TrackType, and that the relationship is unchanging. As such, the exercise table should have a TrackType column.
I suspect, however, that your problem description may be lacking specificity, making it difficult to give you sound advice. For instance, if the TrackType can vary for any given exercise, your TrackType column may belong on the Workout_Sets table. If the relationship between TrackType and Exercise/Workout_Sets is many-to-many, then you will need another junction table.
Your question regarding “over-normalization” depends upon many factors that are specific to your solution. In general, I would say no - the degree of normalization appears to be appropriate.

Handling Many to Many

I'm stuck trying to model a many to many relationship. Here's a representative sample of my issue using an e-commerce model:
+------------+-------------+----------+------------+
| date | customer_id | order_id | address_id |
+------------+-------------+----------+------------+
| 12/1/2019 | 1 | 1 | 1 |
| 12/15/2019 | 2 | 1 | 1 |
| 12/15/2019 | 2 | 2 | 2 |
| 1/1/2020 | 2 | 3 | 1 |
| 1/1/2020 | 1 | 2 | 3 |
| 1/1/2020 | 1 | 3 | 2 |
| 1/2/2020 | 1 | 4 | 1 |
+------------+-------------+----------+------------+
A customer can place many orders.
A customer can ship to multiple addresses.
Addresses can have multiple customers.
How would I model a "household" junction/bridging table? In my data above, customer_id 1 and 2 could possibly be a family or business entity. What if I wanted to know on a given date, how many orders that household/entity placed, how many customers that household represented and how many locations did they ship to?
I think this is the start of how I build this model, but stuck on writing the bridging query.
orders addresses
+-------------+----------+ +-------------+------------+
| customer_id | order_id | | customer_id | address_id |
+-------------+----------+ +-------------+------------+
| 1 | 1 | | 1 | 1 |
| 1 | 2 | | 1 | 2 |
| 1 | 3 | | 1 | 3 |
| 1 | 4 | | 2 | 1 |
| 2 | 1 | | 2 | 2 |
| 2 | 2 | +-------------+------------+
| 2 | 3 |
+-------------+----------+
In a relational database you want to keep all the similar data in separate tables. This helps you with making joins later. I would recommend:

Is it a good idea to have SQL table entries refer to other ids in the same table?

I'm designing a table for product categories for a kinda-e-commerce site. The table currently looks a bit like this:
| id | name | level | value | parent_id |
+----+-------------+-------+-------------+-----------+
| 1 | Food | 0 | food | NULL |
| 2 | Phone | 0 | phone | NULL |
| 3 | Thing | 0 | thing | NULL |
| 4 | Pasta | 1 | pasta | 1 |
| 5 | Apple | 1 | apple | 2 |
| 6 | SubThing | 1 | subthing | 3 |
| 7 | Tagliatelle | 2 | tagliatelle | 4 |
| 8 | iPhone 11 | 2 | iphone_11 | 5 |
| 9 | SubSubThing | 2 | subsubthing | 6 |
Basically I don't want to create a whole new table and map the relationships every time people want to add a new sub-level to the category structure, and rely on level and parent_id columns to let my code know how to do with this category and what its parent is. I'm completely new to model designing and this is the best I could come up with. Is there any downside to this self-referencing structure that I'm just too noob to realize?
If you are certain the sub level (child) will only ever be referenced by that single row or parent then the design should suffice. You may run into issues if multiple child elements need to roll up into that parent entity.

Outer Join multible tables keeping all rows in common colums

I'm quite new to SQL - hope you can help:
I have several tables that all have 3 columns in common: ObjNo, Date(year-month), Product.
Each table has 1 other column, that represents an economic value (sales, count, netsales, plan ..)
I need to join all tables on the 3 common columns giving. The outcome must have one row for each existing combination of the 3 common columns. Not every combination exists in every table.
If I do full outer joins, I get ObjNo, Date, etc. for each table, but only need them once.
How can I achieve this?
+--------------+-------+--------+---------+-----------+
| tblCount | | | | |
+--------------+-------+--------+---------+-----------+
| | ObjNo | Date | Product | count |
| | 1 | 201601 | Snacks | 22 |
| | 2 | 201602 | Coffee | 23 |
| | 4 | 201605 | Tea | 30 |
| | | | | |
| tblSalesPlan | | | | |
| | ObjNo | Date | Product | salesplan |
| | 1 | 201601 | Beer | 2000 |
| | 2 | 201602 | Sancks | 2000 |
| | 5 | 201605 | Tea | 2000 |
| | | | | |
| | | | | |
| tblSales | | | | |
| | ObjNo | Date | Product | Sales |
| | 1 | 201601 | Beer | 1000 |
| | 2 | 201602 | Coffee | 2000 |
| | 3 | 201603 | Tea | 3000 |
+--------------+-------+--------+---------+-----------+
Thx
Devon
It sounds like you're using SELECT * FROM... which is giving you every field from every table. You probably only want to get the values from one table, so you should be explicit about which fields you want to include in the results.
If you're not sure which table is going to have a record for each case (i.e. there is not guaranteed to be a record in any particular table) you can use the COALESCE function to get the first non-null value in each case.
SELECT COALESCE(tbl1.ObjNo, tbl2.ObjNo, tbl3.ObjNo) AS ObjNo, ....
tbl1.Sales, tbl2.Count, tbl3.Netsales

SSRS Hierarchy Recursive total by Row/Column

I've created a very simple employee hierarchy in a matrix, looks something like:
Buildings
-------------------------------------------------
Employee | One | Two | R2D2 | Three |
----------------------------------------------------------------------
Miss Piggy | 15 | | | |
Walter Muppet | | 50 | | |
80's robot | | | 2 | |
Andy Pig | | | | 2 |
Randy Pig | | | | 1 |
Animal Muppet | 15 | 50 | 3 | |
...
...
The SQL is a recursive cte, returns: EmployeeName, ReportsToID, GroupLevel, Building, EmployeeID. In the matrix I have the employee column with these settings to create the hierarchy grouping. To get the count of employees by building in the matrix I have this expression:
=IIF(Fields!GroupLevel.Value="0",
IIF(InScope("Building"),
IIF(InScope("EmployeeName"),sum(Fields!Count.Value, "Building", Recursive),""),""),
IIF(Fields!GroupLevel.Value,Sum(Fields!Count.Value, "EmployeeName", recursive),""))
And so on, you can expand the hierarchy until there are no more managers. The count is the sum of all the direct and indirect reports in that sit in the respective building. etc.
What I want is to have the total of all employees in all buildings for each manager.
I can add row/column totals to get the sum for Miss Piggy, however I also want totals for all buildings for the other managers. Meaning Miss Piggy has people that sit in Buildings: Two, R2D2 and three. Animal Muppet has people that sit in Buildings: One, Two and Three.
Ideally I would like the report to look like this.
Buildings
-------------------------------------------------
Employee | One | Two | R2D2 | Three |
----------------------------------------------------------------------
Miss Piggy | 15 | 100 | 5 | 6 |
Walter Muppet | | 50 | | |
80's robot | | | 2 | |
Andy Pig | | | | 2 |
Randy Pig | | | | 1 |
Animal Muppet | 15 | 50 | | 3 |
... | | | | 2 |
... | | | 1 | |
Any ideas how to accomplish?