Select and group by - calculated field - sql

I'm having some issues to complete a SQL statement in SQL Server 2008.
My 'query1' is the following:
SELECT [Vc_MONTH],
[Vc_STATE],
[Vc_PRODUCT],
SUM ([TOTAL]) as Total_Units,
SUM ([OPEN]) as Open_Units
FROM [test].[dbo].[Tbl_Summary]
GROUP BY [Vc_MONTH],
[Vc_REGION],
[Vc_PRODUCT],
This query selects Month, Region, Product, Sum of Total Units and Sum of Open Units.
I already group by Month, Region and Product. (I have plenty more lines)
This query works.
What I need is another 'query2' that groups by (ALL) the months listed on the table and then an union of this two selects.
At the end I need something like this
query1
|MONTH | STATE | PRODUCT | TOTAL | OPEN |
|:-----|:------|:--------|:------|:-----|
|JAN | CA | PENCIL | 200 | 160 |
|JAN | FL | BOOK | 300 | 280 |
|FEB | CA | PENCIL | 180 | 150 |
|FEB | FL | PENCIL | 250 | 100 |
|MAR | CA | BOOK | 250 | 100 |
|MAR | FL | BOOK | 100 | 50 |
query2 - This is what I need
|MONTH | STATE | PRODUCT | TOTAL | OPEN |
|:-----|:------|:--------|:------|:-----|
|JAN | CA | PENCIL | 200 | 160 |
|JAN | FL | BOOK | 300 | 280 |
|FEB | CA | PENCIL | 180 | 150 |
|FEB | FL | PENCIL | 250 | 100 |
|MAR | CA | BOOK | 250 | 100 |
|MAR | FL | BOOK | 100 | 50 |
UNION
|ALL | CA | PENCIL | 380 | 310 |
|ALL | CA | BOOK | 250 | 100 |
|ALL | FL | PENCIL | 250 | 100 |
|ALL | FL | BOOK | 400 | 330 |
Thanks in advance,
Luis

I think you should just use grouping sets. Much simpler query and no union:
SELECT (CASE WHEN GROUPING([Vc_MONTH]) = 1 THEN 'ALL' ELSE [Vc_MONTH] END) as [Vc_MONTH],
[Vc_STATE], [Vc_PRODUCT],
SUM ([TOTAL]) as Total_Units,
SUM ([OPEN]) as Open_Units
FROM [test].[dbo].[Tbl_Summary]
GROUP BY GROUPING SETS (([Vc_MONTH], [Vc_REGION], [Vc_PRODUCT]),
([Vc_REGION], [Vc_PRODUCT])
);

so you already have query 1:
SELECT [Vc_MONTH],
[Vc_STATE],
[Vc_PRODUCT],
SUM ([TOTAL]) as Total_Units,
SUM ([OPEN]) as Open_Units
FROM [test].[dbo].[Tbl_Summary]
GROUP BY [Vc_MONTH],
[Vc_STATE],
[Vc_PRODUCT]
next you need to GROUP BY Month and Product correct? However, you need to specify a value in the 'Vc_STATE' column so that result sets from the two queries return the same columns.
UNION
SELECT [Vc_MONTH],
'ALL STATES',
[Vc_PRODUCT],
SUM ([TOTAL]) as Total_Units,
SUM ([OPEN]) as Open_Units
FROM [test].[dbo].[Tbl_Summary]
GROUP BY [Vc_MONTH],
[Vc_PRODUCT]

Not a SQL Server Guru by any stretch, but I think it has a with clause:
with monthly as (
SELECT
[Vc_MONTH], [Vc_STATE], [Vc_PRODUCT],
SUM ([TOTAL]) as Total_Units,
SUM ([OPEN]) as Open_Units
FROM [test].[dbo].[Tbl_Summary]
GROUP BY
[Vc_MONTH], [Vc_STATE], [Vc_PRODUCT]
)
select
[Vc_MONTH], [Vc_STATE], [Vc_PRODUCT],
Total_Units, Open_Units
from monthly
union all
select
'*ALL', [Vc_STATE], [Vc_PRODUCT],
sum (Total_Units), sum (Open_Units)
from monthly
group by [Vc_STATE], [Vc_PRODUCT]

Related

Calculate total amount PGSQL

query which calculates the total amount in dollars of stolen goods for each month for restricted and neutral items.
I have 2 tables
first
| UPC | item | in_stock | price | ship_day | class |
1 | 101 | 'generator' | 16 | 5999 | '12-1-2065'| 'restricted'
2 | 102 | 'blank tape' | 30 | 3000 | '12-1-2065'| 'neutral'
second
| UPC | unit_stolen |
1 | 101 | 4 |
1 | 401 | 2 |
If I understand correctly, this is basically a join and group by:
select date_trunc('mon', f.ship_day) as yyyymm,
sum(f.price * s.unit_stolen) filter (where f.class = 'restricted'),
sum(f.price * s.unit_stolen) filter (where f.class = 'neutral')
from first f join
second s
on f.upc = s.upc
group by date_trunc('mon', f.ship_day)

GET DATA FROM TXT SUM GROUP BY AND SUBTRACT

Trying to get data from txt file which contains buys and sells like in the format below.
I want to group by items and subtract each other.
I made three queries like totalin and totalout and stock but when I subtract out from in, some items are missing which has not been sold.
This is the data table
+------+---------+--------+
| TYPE | ITEM | AMOUNT |
+------+---------+--------+
| BUY | APPLE | 100 |
| BUY | ORANGE | 100 |
| BUY | APPLE | 200 |
| BUY | ORANGE | 200 |
| SELL | APPLE | 50 |
| SELL | APPLE | 50 |
| SELL | ORANGE | 100 |
| SELL | ORANGE | 100 |
| BUY | COCONUT | 50 |
| SELL | BANANE | 30 |
+------+---------+--------+
I want this output
+---------+--------+
| ITEM | AMOUNT |
+---------+--------+
| APPLE | 200 |
| BANANE | -30 |
| COCONUT | 50 |
| ORANGE | 100 |
+---------+--------+
I made 3 queries for the result that i want, but unfortunately I am stuck.
Here is my queries
QUERY 1 TOTAL IN:
SELECT DATA.TYPE, DATA.ITEM, Sum(DATA.AMOUNT) AS TOTALIN
FROM DATA
GROUP BY DATA.TYPE, DATA.ITEM
HAVING (((DATA.TYPE)="BUY"));
QUERY 2 TOTAL OUT:
SELECT DATA.TYPE, DATA.ITEM, Sum(DATA.AMOUNT) AS TOTALOUT
FROM DATA
GROUP BY DATA.TYPE, DATA.ITEM
HAVING (((DATA.TYPE)="SELL"));
QUERY 3 STOCK:
SELECT DATA.ITEM, [BUY]![TOTAL_IN]-[SELL]![TOTAL_OUT] AS STOK
FROM (DATA INNER JOIN BUY ON DATA.ITEM = BUY.ITEM) INNER JOIN SELL ON DATA.ITEM = SELL.ITEM
GROUP BY DATA.ITEM, [BUY]![TOTAL_IN]-[SELL]![TOTAL_OUT];
How can I made a query which shows the rest as stock.
Many thanks.
You can sum in one go like:
SELECT ITEM,
Sum(iif(data.type = "BUY", AMOUNT, -AMOUNT)) AS Stock
FROM DATA
GROUP BY ITEM;
You can think of SELL as -ve and BUY as +ve Amount.
Then the query becomes as follows
select item
,sum(case when type='BUY' then Amount
when type='SELL' then -Amount
end) as Amount
from data_table
group by item
In MsAccess, you can apply an if-logic block using the iif function and run the query in one step as below.
SELECT item,
SUM(iif ([type] = "SELL", (-1 * Amount), Amount)) as amounts
FROM data
GROUP BY item

Duplicate records upon joining table

I am still very new to SQL and Tableau however I am trying to work myself towards achieving a personal project of mine.
Table A; shows a table which contains the defect quantity per product category and when it was raised
+--------+-------------+--------------+-----------------+
| Issue# | Date_Raised | Category_ID# | Defect_Quantity |
+--------+-------------+--------------+-----------------+
| PCR12 | 11-Jan-2019 | Product#1 | 14 |
| PCR13 | 12-Jan-2019 | Product#1 | 54 |
| PCR14 | 5-Feb-2019 | Product#1 | 5 |
| PCR15 | 5-Feb-2019 | Product#2 | 7 |
| PCR16 | 20-Mar-2019 | Product#1 | 76 |
| PCR17 | 22-Mar-2019 | Product#2 | 5 |
| PCR18 | 25-Mar-2019 | Product#1 | 89 |
+--------+-------------+--------------+-----------------+
Table B; shows the consumption quantity of each product by month
+-------------+--------------+-------------------+
| Date_Raised | Category_ID# | Consumed_Quantity |
+-------------+--------------+-------------------+
| 5-Jan-2019 | Product#1 | 100 |
| 17-Jan-2019 | Product#1 | 200 |
| 5-Feb-2019 | Product#1 | 100 |
| 8-Feb-2019 | Product#2 | 50 |
| 10-Mar-2019 | Product#1 | 100 |
| 12-Mar-2019 | Product#2 | 50 |
+-------------+--------------+-------------------+
END RESULT
I would like to create a table/bar chart in tableau that shows that Defect_Quantity/Consumed_Quantity per month, per Category_ID#, so something like this below;
+----------+-----------+-----------+
| Month | Product#1 | Product#2 |
+----------+-----------+-----------+
| Jan-2019 | 23% | |
| Feb-2019 | 5% | 14% |
| Mar-2019 | 89% | 10% |
+----------+-----------+-----------+
WHAT I HAVE TRIED SO FAR
Unfortunately i have not really done anything, i am struggling to understand how do i get rid of the duplicates upon joining the tables based on Category_ID#.
Appreciate all the help I can receive here.
I can think of doing left joins on both product1 and 2.
select to_char(to_date(Date_Raised,'d-mon-yyyy'),'mon-yyyy')
, (p2.product1 - sum(case when category_id='Product#1' then Defect_Quantity else 0 end))/p2.product1 * 100
, (p2.product2 - sum(case when category_id='Product#2' then Defect_Quantity else 0 end))/p2.product2 * 100
from tableA t1
left join
(select to_char(to_date(Date_Raised,'d-mon-yyyy'),'mon-yyyy') Date_Raised
, sum(Comsumed_Quantity) as product1 tableB
where category_id = 'Product#1'
group by to_char(to_date(Date_Raised,'d-mon-yyyy'),'mon-yyyy')) p1
on p1.Date_Raised = t1.Date_Raised
left join
(select to_char(to_date(Date_Raised,'d-mon-yyyy'),'mon-yyyy') Date_Raised
, sum(Comsumed_Quantity) as product2 tableB
where category_id = 'Product#2'
group by to_char(to_date(Date_Raised,'d-mon-yyyy'),'mon-yyyy')) p2
on p2.Date_Raised = t1.Date_Raised
group by to_char(to_date(Date_Raised,'d-mon-yyyy'),'mon-yyyy')
By using ROW_NUMBER() OVER (PARTITION BY ORDER BY ) as RN, you can remove duplicate rows. As of your end result you should extract month from date and use pivot to achieve.
I would do this as:
select to_char(date_raised, 'YYYY-MM'),
(sum(case when product = 'Product#1' then defect_quantity end) /
sum(case when product = 'Product#1' then consumed_quantity end)
) as product1,
(sum(case when product = 'Product#2' then defect_quantity end) /
sum(case when product = 'Product#2' then consumed_quantity end)
) as product2
from ((select date_raised, product, defect_quantity, 0 as consumed_quantity
from a
) union all
(select date_raised, product, 0 as defect_quantity, consumed_quantity
from b
)
) ab
group by to_char(date_raised, 'YYYY-MM')
order by min(date_raised);
(I changed the date format because I much prefer YYYY-MM, but that is irrelevant to the logic.)
Why do I prefer this method? This will include all months where there is a row in either table. I don't have to worry that some months are inadvertently filtered out, because there are missing production or defects in one month.

Comparing SUM of values with different tables in SQL Server

I have two tables holding similar values, and I need to compare the two and find the differences between them:
SQL FIDDLE - http://sqlfiddle.com/#!6/7412e/9
Now you can see there is a difference between between the 2 tables for the figures in Jun-17.
AS you can see (as a total for everyone) table 1 has £75 for June but table 2 has £125 for june.
The result I'm looking for is when amounts are summed together and compared between tables on a monthly basis, if there is a difference in amount between the two tables I want it listed under 'Unknown'.
| MonthYear | Person | Amount | Month total
+-----------+--------+--------+--------------
| Jun-17 | Sam | 25 | 75(Table1)
| Sep-17 | Ben | 50 | 50(Table2)
| Jun-17 | Tom | 50 | 75(Table1)
| Jun-17 | Sam | 25 | 125(Table2)
| Sep-17 | Ben | 50 | 50(Table2)
| Jun-17 | Tom | 50 | 125(Table2)
| Jun-17 | | 50 | 125(Table2)
Now when there is a difference between the amount total over a month I want the difference to be classed as unknown
e.g
| MonthYear | Person | Amount | Month total
+-----------+--------+--------+--------------
| Jun-17 | Sam | 25 | 75(Table1)
| Sep-17 | Ben | 50 | 50(Table2)
| Jun-17 | Tom | 50 | 75(Table1)
| Jun-17 | Sam | 25 | 125(Table2)
| Sep-17 | Ben | 50 | 50(Table2)
| Jun-17 | Tom | 50 | 125(Table2)
| Jun-17 | Unknown| 50 | 125(Table2)
I understand that you could create a case when the person is null to display unknown but i need it to be specifically calculated on the difference between the 2 tables on a monthly calculation.
Does this make sense to anyone, its really hard to explain.
Generally, in any FROM clause a table name can be replaced with another SELECT as long as you give it a corelation name (t1 and t2 in this one):
SELECT t1.MonthYear, t1.AmountT1, t2.AmountT2, t1.amountT1 - isnull(t2.amountT2, 0) as Unknown'
from
( SELECT
MonthYear,
SUM(Amount) AS [AmountT1]
FROM
Invoice
GROUP BY MonthYear) t1
left outer join
( SELECT
MonthYear,
SUM(Amount) AS [AmountT2]
FROM
Invoice2
GROUP BY MonthYear) t2 on t2.MonthYear = t1.MonthYear

SQL Query to Return SUMS and Count Ordered by Date

I have the two following tables:
Table 1
Table 2
What I want to do is to have a query that returns a SUM of PIT_VALORTOTAL, PIT_VOLUME and a count of PED_IDPESSOA per date. What I have so far is:
SELECT SUM(PIT_VALORTOTAL) AS VALORTOTAL, SUM(PIT_VOLUME) AS VOLUME, COUNT(DISTINCT PED_IDPESSOA) AS PESSOA FROM PEDIDOS_ITENS INNER JOIN PEDIDOS ON PIT_IDPEDIDO = PED_ID;
And it returns the sums and the count correctly, but I don't have a clue on how to get these seperatly per dates. So what I have is this:
VALORTOTAL | VOLUME | PESSOA |
49783.2000000 | 679780.360000| 11 |
And what I want is something like:
| DATE | VALORTOTAL | VOLUME | PESSOA |
| 2017-09-03| 1012,00 | 1209 | 12 |
| 2017-09-03| 2012,00 | 1450 | 10 |
| 2017-09-03| 3016,00 | 2500 | 20 |
| 2017-09-03| 3016,00 | 3200 | 5 |
| 2017-09-03| 2016,00 | 4000 | 9 |
You just need group by:
SELECT PED_DATA, SUM(PIT_VALORTOTAL) AS VALORTOTAL, SUM(PIT_VOLUME) AS VOLUME,
COUNT(DISTINCT PED_IDPESSOA) AS PESSOA
FROM PEDIDOS_ITENS pi INNER JOIN
PEDIDOS p
ON PIT_IDPEDIDO = PED_ID
GROUP BY PED_DATA
ORDER BY PED_DATA