Cross Join is creating a Loop - sql

I have three tables, I need to make a CROSS JOIN between them to display the IDs and names of the products and the stores that sell them, here is an example of how now
TABLE_PRODUCT
ID_PRODUCT | NAME_PRODUCT
1 | Addidas Super Star
2 | Calvin Klein BAG
TABLE_STORE
ID_STORE | NAME_STORE
1 | ThE 98
2 | C&A
TABLE_PROD_STOR
ID_STORE | ID_PROD
1 | 1
2 | 2
And I need the result in the format:
ID STORE | STORE | ID PRODUCT | PRODUCT |
1 | ThE 98 | 1 | Addidas Super Star |
2 | C&A | 2 | CALVIN KLEIN HAT |
My biggest problem is that when I do the CROSS JOIN, the names are repeated twice each. What is the solution?

Select
y.ID_STORE ,
y.NAME_STORE store ,
x.ID_PRODUCT,
x.NAME_PRODUCT product
from
TABLE_PRODUCT x inner join
TABLE_STORE y
on x.ID_PRODUCT =y.ID_STORE
inner join TABLE_PROD_STOR z
on x.ID_PRODUCT =z.ID_STORE

Related

Trying to join a table of individuals to a table of couples, give a family ID and not time out the server

I have one table with fake individual tax records like so (one row per filer):
T1:
+-------+---------+---------+
| Person| Spouse | Income |
+-------+---------+---------+
| 1 | 2 | 34000 |
| 2 | 1 | 10000 |
| 3 | NULL | 97000 |
| 4 | 6 | 11000 |
| 5 | NULL | 25000 |
| 6 | 4 | 100000 |
+-------+---------+---------+
I have a second table which has tax 'families', a single individual or married couple (one line per tax 'family').
T1_Family:
+-------- -+-------+---------+
| Family_id| Person| Spouse |
+-------- -+-------+---------+
| 2 | 2 | 1 |
| 3 | 3 | NULL |
| 5 | 5 | NULL |
| 6 | 6 | 4 |
+------ ---+-------+---------+
Family = max(Person) within a couple
The idea of joining the two is for example, to sum the income of 2 people in one tax family (aggregate to the family level).
So, I've tried the following:
select *
into family_table
from
(
(select * from T1_family)a
join
(select * from T1)b
on a.family = b.person **or a.spouse = b.person**
)
where family_id is not null and person is not null
What I should get (and I do get when I select 1 random couple) is one line per individual where I can then group by family_id and sum income, pension contributions, etc. BUT SQL times out before the tables can be joined. The part in bold is what's slowing down the process but I'm not sure what else to do.
Is there an easier way to group by family?
It is simpler to put the data on one row:
select a.*, p.income as person_income, s.income as spouse_income
into family_table
from t1_family a left join
t1 p
on a.person = p.person lef tjoin
t1 s
on a.spouse = s.person;
Of course, you can add them together as well.

Relational database - adding products

I have the following situation, namely I need to make a database,
in which I will store products that the user added to breakfast,
lunch, midday meal and dinner ON A SPECIFIC DAY.
I have a problem with the construction of such a relational database.
I currently have this combination of two tables:
It seems to me that I need 3 tables here in which
the products themselves will be placed, but I have no idea how
I can combine these 3 tables to get queries
products depending on the type of meal (breakfast, lunch ..) and date (the day they were added)
Yes, you should have a Products table that should have the 5 last columns you are showing in your second table (Orders?). And remove them from the Orders table such that it only has the IDs referencing the Meal and Product and the Date.
Then you can do the following:
SELECT o.Date, m.Meal_Name, p.Product_Name, p.Carbohydrates,
p.Protein, p.Fat, p.Calories
FROM Orders o
INNER JOIN Meals m ON o.MealID = m.MealID
INNER JOIN Products p ON o.ProductID = p.ProductID
ORDER BY o.date, m.Meal_Name, p.Product_Name
Note that this will allow you to easly change the parameters (such as fat or Carbohydrates for a Product and have it appear in all records for that product.
While there is certainly plenty of room to interpretation here and you may only want to go so far in normalizing your data, I think a better option would be:
meals:
id | user_id | category_id | date
1 | 1 | 1 | 2019-09-03
meal_category
id | name
1 | breakfast
2 | lunch
3 | dinner
products
id | name | carbs | protein | fat | calories
1 | apple| 10 | 5 | 0 | 30
2 | cat | 0 | 20 | 5 | 80
3 | ham | 10 | 30 | 10 | 160
meal_products
meal_id | product_id
1 | 1
1 | 2
Bringing this together:
SELECT meals.id, meals.user_id, meal.date, meal_category.name, product.name, product.carbs, products.protein, products.fat, products.calories
FROM meals
INNER JOIN meal_category ON meals.category_id = meal_category.id
INNER JOIN meal_produts ON meals.id = meal_products.meal_id
INNER JOIN products ON meal_products.product_id = products.id
Which would yeild
+-----------+----------------+------------+---------------------+---------------+----------------+-------------------+---------------+-------------------+
| meals.id, | meals.user_id, | meal.date, | meal_category.name, | product.name, | product.carbs, | products.protein, | products.fat, | products.calories |
+-----------+----------------+------------+---------------------+---------------+----------------+-------------------+---------------+-------------------+
| 1 | 1 | 9/3/2019 | breakfast | apple | 10 | 5 | 0 | 30 |
| 1 | 1 | 9/3/2019 | breakfast | cat | 0 | 20 | 5 | 80 |
+-----------+----------------+------------+---------------------+---------------+----------------+-------------------+---------------+-------------------+

SQL Query to Work out Every Product Combination

I require a SQL query to work out every product combination.
I have three product categories (game, accessory, upgrade) and products assigned to each of these three categories:
+----+------------+-----------+------------+
| id | category | product | prod_code |
+----+------------+-----------+------------+
| 1 | game | GTA | 100 |
| 2 | game | GTA1 | 200 |
| 3 | game | GTA2 | 300 |
| 4 | accessory | Play Pad | 400 |
| 5 | accessory | Xbox Pad | 500 |
| 6 | upgrade | Memory | 600 |
| 6 | upgrade | drive | 700 |
+----+------------+-----------+------------+
I want to take one product from each of the categories and work out every single combination:
+----+--------------+
| id | combinations |
+----+--------------+
| 1 | 100,400,600 |
| 2 | 100,500,600 |
| 3 | 100,400,700 |
| 4 | 100,500,700 |
| ? | etc |
+----+--------------+
How would I go about doing this?
Thanks in advance, Stuart
Use a CROSS JOIN:
SELECT CONCAT(t1.[prod_code], ',',
t2.[prod_code], ',',
t3.[prod_code])
FROM (
SELECT [prod_code]
FROM mytable
WHERE category = 'game') AS t1
CROSS JOIN (
SELECT [prod_code]
FROM mytable
WHERE category = 'accessory') AS t2
CROSS JOIN (
SELECT [prod_code]
FROM mytable
WHERE category = 'upgrade') AS t3
ORDER BY t1.[prod_code], t2.[prod_code], t3.[prod_code]
CROSS JOIN of derived tables, one for each category, produces the following cartesian product: 'game' products x 'accessory' products x 'upgrade' products
Demo here

Using COUNT in nested SELECTS

I'm trying to count the number of instances of a value in a column and return it in another column. I've successfully done the calculation with a hard coded value but can't figure out how to get a variable from the main SELECT into the COUNT.
In the sample data at the bottom, CommissionRate shows the number of times the DealInstanceOID value in that row shows up in the DealInstanceOID column. My hard coded solution works for all of these values, but getting this to happen dynamically is mystifying me. The DealInstanceOID variable is out of the scope of the nested SELECT and I'm unsure of how to work around that.
I posted this question earlier and had some complaints about how my tables are joined - wasn't able to get any more feedback from those posters and I am reposting as they suggested.
SELECT
D.DealOID
DD.DealInstanceOID
, CommissionRate = (SELECT (DealInstanceOID COUNT(*) FROM dbo.DealDetail WHERE DealInstanceOID = 4530))
, Commission = CONVERT(MONEY,C.Commission,1)
FROM dbo.Book AS B WITH(NOLOCK)
INNER JOIN Contract as C WITH(NOLOCK) ON B.BookOID = C.BookOID
INNER JOIN Deal as D WITH(NOLOCK)ON C.ContractOID = D.ContractOID
INNER JOIN DealInstance DI WITH(NOLOCK) ON DI.DealOID = D.DealOID
INNER JOIN DealDetail AS DD WITH(NOLOCK)ON DD.DealInstanceOID = DI.DealInstanceOID
GROUP BY
DD.DealInstanceOID
, D.DealOID
, C.Commission
, B.BookOID
ORDER BY DealOID ASC
DealOID |Commission |CommissionRate|Commission/Rate|DealInstanceOID
101 | $1000 | 5 | $200.00 | 4530
101 | $1000 | 5 | $200.00 | 4530
101 | $1000 | 5 | $200.00 | 4530
101 | $1000 | 5 | $200.00 | 4530
101 | $1000 | 5 | $200.00 | 4530
101 | $5000 | 6 | $833.33 | 4531
102 | $5000 | 6 | $833.33 | 4531
102 | $5000 | 6 | $833.33 | 4531
102 | $5000 | 6 | $833.33 | 4531
102 | $5000 | 6 | $833.33 | 4531
102 | $5000 | 6 | $833.33 | 4531
103 | $6000 | 3 | $2,000.00 | 4540
103 | $6000 | 3 | $2,000.00 | 4540
103 | $6000 | 3 | $2,000.00 | 4540
Two problems with your scalar sub-select statement. One is a syntax error and the other is referencing. Fix them as follows:
CommissionRate = (SELECT COUNT(*) FROM dbo.DealDetail as s WHERE s.DealInstanceOID = dd.DealInstanceOID)
You should be able to reference it by the table alias and column name:
...
WHERE dbo.DealDetail.DealInstanceOID = DD.DealInstanceOID))
...
Using a join instead of a select for every row.
The key is to use a CTE. As you can see below the result is two selects against the database as opposed to one for every row.
WITH counts AS
( -- This will give a virtual table (CTE) with ID and count
SELECT DealInstanceOID, COUNT(*) as C
FROM dbo.DealDetail
GROUP BY DealInstanceOID
)
SELECT
D.DealOID,
DI.DealInstanceOID,
counts.C AS CommissionRate,
CONVERT(MONEY,C.Commission,1) AS Commission
FROM dbo.Book AS B WITH(NOLOCK)
JOIN Contract as C WITH(NOLOCK) ON B.BookOID = C.BookOID
JOIN Deal as D WITH(NOLOCK)ON C.ContractOID = D.ContractOID
JOIN DealInstance DI WITH(NOLOCK) ON DI.DealOID = D.DealOID
JOIN counts ON DI.DealInstanceOID = counts.DealInstanceOID
GROUP BY DI.DealInstanceOID, D.DealOID, C.Commission, B.BookOID
ORDER BY DealOID ASC

Getting Sum of MasterTable's amount which joins to DetailTable

I have two tables:
1. Master
| ID | Name | Amount |
|-----|--------|--------|
| 1 | a | 5000 |
| 2 | b | 10000 |
| 3 | c | 5000 |
| 4 | d | 8000 |
2. Detail
| ID |MasterID| PID | Qty |
|-----|--------|-------|------|
| 1 | 1 | 1 | 10 |
| 2 | 1 | 2 | 20 |
| 3 | 2 | 2 | 60 |
| 4 | 2 | 3 | 10 |
| 5 | 3 | 4 | 100 |
| 6 | 4 | 1 | 20 |
| 7 | 4 | 3 | 40 |
I want to select sum(Amount) from Master which joins to Deatil where Detail.PID in (1,2,3)
So I execute the following query:
SELECT SUM(Amount) FROM Master M INNER JOIN Detail D ON M.ID = D.MasterID WHERE D.PID IN (1,2,3)
Result should be 20000. But I am getting 40000
See this fiddle. Any suggestion?
You are getting exactly double the amount because the detail table has two occurences for each of the PIDs in the WHERE clause.
See demo
Use
SELECT SUM(Amount)
FROM Master M
WHERE M.ID IN (
SELECT DISTINCT MasterID
FROM DETAIL
WHERE PID IN (1,2,3) )
What is the requirement of joining the master table with details when you have all your columns are in Master table.
Also, isnt there any FK relationhsip defined on these tables. Looking at your data it seems to me that there should be FK on detail table for MasterId. If that is the case then you do not need join the table at all.
Also, in case you want to make sure that you have records in details table for the records for which you need sum and there is no FK relationship. Then you could give a try for exists instead of join.