SQL Server, finding the SUM of a foreign key column - sql-server

I currently have 3 tables.
Table 1: customers
id(PK) name surname
----------------------------------
1 name1 surname1
2 name2 surname2
3 name3 surname3
4 name4 surname4
Table 2: sales
id(FK) game(FK) price(FK)
-----------------------------
1 1 1
2 4 4
3 4 4
4 3 3
1 3 3
2 3 3
3 2 2
Table 3: stock
id(FK) game price
-----------------------------
1 game1 20
2 game2 30
3 game3 40
4 game4 50
What I'm looking to do is find the sum of all the sales listed in the sales table (table 2).
So far, I can display a table showing how much money each game has made in total but cannot get the overall total of sales to display.
I have tried
select sum(sales.price)
from sold
However, this is just calculating the sum of the foreign key (in this case it would be 20). However, I want it to display 270.

You need to join the stock and sales tables to get the correct price of each of the items sold.
Select sum(stock.price) from sales
inner join stock on sales.game = stock.id

Related

DAX - Divide a column over itself with different filters to get percentages

In power Pivot I have tables along the lines of:
Table 1
Year
Month
Branch_ID
Store_ID
Article
Value
2022
10
1
1
Sales
100
2022
10
1
2
Sales
200
2022
10
1
2
Operating expenses
50
2022
10
1
1
Operating expenses
80
2022
10
1
2
Cost of Sales
20
2022
10
1
1
Cost of Sales
30
Table 2
Year
Month
Branch_ID
Store_ID
Article
Value
2022
10
1
1
Sales_Ecomm
20
2022
10
1
2
Sales_Ecomm
15
Table 3
| Article |
|--------------------|
| Sales |
| Operating expenses |
| Cost of Sales |
| Sales_Ecomm |
There are multiple branches and months, so these columns may not be ignored.
Table 1 and table 2 are separate. Table 3 is connected to both so that I could build a pivot table.
In the pivot table I want to have all articles re-evaluated as percentage of Sales, i.e. I am trying to get a pivot table along the lines of:
Store ID
Sales
Operating expenses
Cost of Sales
Sales_Ecomm
Value
% of sales
Value
% of sales
Value
% of sales
Value
% of sales
1
100
100.00%
80
80.00%
30
30.00%
20
20.00%
2
200
100.00%
50
25.00%
20
10.00%
15
7.50%
I have a measure
Val. := sum(table1[Value]) + sum(table2[value])
which seems to be working for absolute values of the articles.
However, I can't seem to come up with an appropriate DAX measure for percentages. I have tried:
%_of_Sales := [Val.] / calculate([Val.], filter(table3; table3[Article]="Sales"))
but it only counts Sales as percentage of Sales (100%), yielding #NUM! for other articles in the pivot table.
How do I define a ratio measure so that every article is evaluated against Sales?
You're missing a crucial ALL:
=
DIVIDE(
[Val.],
CALCULATE(
[Val.],
FILTER(
ALL( table3 ),
table3[Article] = "Sales"
)
)
)
which is equivalent to:
=
DIVIDE(
[Val.],
CALCULATE(
[Val.],
table3[Article] = "Sales"
)
)

SQL query / CTE for Association table having many to many relationships

I have two tables A and B. B can have many records of A but B will not have any records of A
One-to-many -> one way
Now
Table A:
Id Name
----------
1 Rule1
2 Rule2
Table B:
Id TargetedTypeId TargetedId TargetingType TargetingId Status
TargetedType table:
Id Name
--------------
1 Users
2 Employee
TargetingType table:
Id Name
-----------------
1 Vegetable
2 Fruits
Users table:
Id Name
--------------
1 Abc
2 xyz
Vegetables table:
Id Name
-----------------
1 Onion
2 Potato
Fruits table:
Id Name
---------------
1 Apple
2 Orange
Table B will have rows like this:
Id | TargetedTypeId | TargetedId (Table A Ids) | TargetingType | TargetingId | Status
-----------------------------------------------------------------------
1 1 2 1 2 1
2 1 2 1 1 1
3 1 2 2 1 1
4 1 2 2 2 1
Please hep me to write a query which will fetch A tables entries present in B with status 1 and fetch all targeting types and get fruit details if its fruit and if vegetable if its vegetable type which is TargetingType and fetch its details with respective table fruit/vegetable with Pagination

Sum values from multiple tables grouping by a common column

I have three tables in MS SQL Server 2014. Each of them holds a couple of numeric values, a description and a date. For the sake of brevety, let's assume the following tables:
table "beverages"
day beverage amount
---------- -------- ------
2018-12-01 water 2
2018-12-01 tea 1
2018-12-01 coffee 7
2018-12-02 water 4
2018-12-02 tea 2
table "meals"
day meal amount
---------- ------ ------
2018-12-01 burger 1
2018-12-01 bread 2
2018-12-02 steak 1
table "fruit"
day fruit amount
---------- ------ ------
2018-12-01 apple 4
2018-12-01 banana 1
2018-12-02 apple 2
Then I have another table holding only a list of dates.
table "dates"
day
----------
2018-12-01
2018-12-02
What I need is a query that returns one row for each of the rows in the dates table, and in each row has the date, the total amount of beverages, the total amount of meals and the total amount of fruit for that day. I do not care for the different types of beverages, meals and fruit, just the sum. The result should be:
expected result
day beverages meals fruit
---------- ----------- ----------- -----------
2018-12-01 10 3 5
2018-12-02 6 1 2
But instead I receive
received result
day beverages meals fruit
---------- ----------- ----------- -----------
2018-12-01 40 18 30
2018-12-02 6 2 4
I already know what the problem is, just not how to fix it. Even worse, I'm sure that I knew the answer once, but now I can't even figure the right search terms to make Google tell me...
When I do the query like this (I used table variables for testing)
SELECT
[d].[day]
,SUM([b].[amount]) AS [beverages]
,SUM([m].[amount]) AS [meals]
,SUM([f].[amount]) AS [fruit]
FROM #dates AS [d]
LEFT OUTER JOIN #beverages AS [b]
ON [d].[day] = [b].[day]
LEFT OUTER JOIN #meals AS [m]
ON [d].[day] = [m].[day]
LEFT OUTER JOIN #fruit AS [f]
ON [d].[day] = [f].[day]
GROUP BY [d].[day]
it sums each row from the different tables more than once, because it returns every possible combination of the three tables. Removing the SUM() and GROUP BY proves that:
day beverages meals fruit
---------- ----------- ----------- -----------
2018-12-01 2 1 4
2018-12-01 2 1 1
2018-12-01 2 2 4
2018-12-01 2 2 1
2018-12-01 1 1 4
2018-12-01 1 1 1
2018-12-01 1 2 4
2018-12-01 1 2 1
2018-12-01 7 1 4
2018-12-01 7 1 1
2018-12-01 7 2 4
2018-12-01 7 2 1
2018-12-02 4 1 2
2018-12-02 2 1 2
So, what do I need to change in the query to make it sum the values for each of the three tables without multiplying it with the number of the rows in the other tables?
Group the Tables before joining like so:
SELECT
[d].[day]
,[b].[amount] AS [beverages]
,[m].[amount] AS [meals]
,[f].[amount] AS [fruit]
FROM #dates AS [d]
LEFT OUTER JOIN (SELECT day, SUM(amount) as amount FROM #beverages GROUP BY day) AS [b]
ON [d].[day] = [b].[day]
LEFT OUTER JOIN (SELECT day, SUM(amount) as amount FROM #meals GROUP BY day) AS [m]
ON [d].[day] = [m].[day]
LEFT OUTER JOIN (SELECT day, SUM(amount) as amount FROM #fruit GROUP BY day) AS [f]
ON [d].[day] = [f].[day]
How about a PIVOT instead?
Example
Select *
From (
Select day,Item='beverage',amount from beverages
Union All
Select day,Item='meals' ,amount from meals
Union All
Select day,Item='fruit' ,amount from fruit
) src
Pivot ( sum(amount) for Item in ([beverages],[meals],[fruit]) ) pvt

Latest record for each user number?

I did search, but the uniqueness of each question makes it hard for me to "translate" it for my dataset.
I have table A named: CLOGS17
With a sub-set of the data and fields shown:
SERIALNO EVDATE SYSNO AREA USRNO
4 2017-01-01 02:03:48.000 1 4 10
4 2017-01-01 02:09:00.000 1 4 10
4 2017-01-01 02:24:44.997 1 6 10
4 2017-01-01 02:56:50.000 1 2 18
5 2017-08-08 02:03:48.000 1 4 10
5 2017-01-09 02:09:00.000 1 4 10
6 2017-04-03 02:24:44.997 1 6 10
8 2017-05-05 02:56:50.000 1 2 18
My goal is to retrieve all records where the combination of SERIALNO + SYSNO + AREA + USRNO has not been used in the last 30 days (inactive user essentiallY) so I can delete that USRNO.
Desired output from above data would be (newest record for each SERIALNO, SYSNO, AREA, and USRNO distinct combination):
SERIALNO EVDATE SYSNO AREA USRNO
4 2017-01-01 02:09:00.000 1 4 10
4 2017-01-01 02:24:44.997 1 6 10
4 2017-01-01 02:56:50.000 1 2 18
5 2017-08-08 02:03:48.000 1 4 10
6 2017-04-03 02:24:44.997 1 6 10
8 2017-05-05 02:56:50.000 1 2 18
I am then able to get only those within the last 30 days.
Given the table data below ("Table B"), it is a list of all stored users:
SERIALNO CONTID SYSNO AREA USRID
36 001 1 * 1
36 001 1 * 18
36 001 1 * 2
36 001 1 * 29
36 001 1 * 36
36 001 1 1 10
This table contains ALL users in the system.
How can I return all the users from Table B that have not been used for a given CONTID, SYSNO, and AREA?
For the first part of your question it would be as simples as a group by of a select on the desired fields:
SELECT SERIALNO,
SYSNO,
AREA,
USRNO,
MAX(EVDATE)
FROM CLOGS17
GROUP BY SERIALNO,
SYSNO,
AREA,
USRNO
Since you didn't provide enough information about the second part. This query will give you the output you show in your question.
So, to get all users that doesn't meet your 30 days criteria (whatever it are), you just do a left join of you user table with the above query seeking the nulls for the query above, like this:
SELECT *
FROM tableb tb LEFT JOIN
(SELECT SERIALNO,
SYSNO,
AREA,
USRNO,
MAX(EVDATE)
FROM CLOGS17
GROUP BY SERIALNO,
SYSNO,
AREA,
USRNO) a
ON tb.SERIALNO = a.SERIALNO,
AND tb.SYSNO = a.SYSNO
AND tb.USRNO = a.USRNO
WHERE a.AREA is null

Query that shows data depending of 2 columns

I'm working on a Report in Visual Basic. It has a query to show the information below.
So, I need a query that sets all the rows that are between 2 values that the user choose. The problem is that the value exists several times.
To explain better:
ID Category_ID SubCategory_ID Description Period_ID Data
----------- ----------- -------------- ------------- ----------- --------
1 1 1 PRUEBA 1 100.00
2 2 5 Total 1 2.00
3 1 1 sgsdg 2 25.00
4 1 1 fsdf 2 5.00
5 1 1 sdf 2 54.00
There will be a lot more of Period_ID. So, if the user chooses Period 1 and Period 5, it will show all the data between Period 1 and Period 5 (i.e. Period1, Period2, Period3, Period4 and Period5).
Is there a query which can do this?
I appreciate your help!
I would do:
Select *
FROM SAMPLE_TABLE
WHERE SAMPLE_TABLE.PERIOD_ID
IN (SELECT ID FROM PERIOD
WHERE ID >= 1 AND ID <= 5)
This is called a subquery. This relies on you have a period table, which I assume you have

Resources