SQL how sum if value - sql

Hi I try to need to sum values and if there is more than 20 there shouldbe written 20 else should be number.
I don't know what i make wrong:
SELECT
ta6.product_product_id AS ID,
ta6.product_manufacture_code AS Code,
SUM(CASE WHEN ta3.stock_quantity >= 20 THEN 20 ELSE ta3.stock_quantity END) AS Quantity,
ta4.price_value AS Price,
ta5.Attribute_Value AS Sizer,
ta6.Procut_product_name AS Name,
ta7.Attribute_Value AS produce
FROM
product ta6
LEFT JOIN stock ta3 ON
ta3.stock_id = ta6.product_id
LEFT JOIN price ta4 ON
ta4.price_id = ta6.product_id
AND ta4.price_type = 2
LEFT JOIN Attributes ta5 ON
ta5.Attributes_product_Id = ta6.product_id
LEFT JOIN Attributes ta7 ON
ta7.Attributes_product_Id = ta6.product_id
WHERE
( ta3.stock_wharehouse_id = 1
AND ta5.Attrib_id = 54
AND ta7.Attrib_id = 25 )
GROUP BY
ta6.product_manufacture_code,
ta6.product_product_id
ta4.price_value,
ta5.Attribute_Value,
ta6.product_product_name ,
ta7.Attribute_Value;
Table stock_quantity looks like:
Stock_table image
How to sum it ??

Like this?
CASE WHEN SUM(ta3.stock_quantity) >= 20
THEN 20
ELSE SUM(ta3.stock_quantity)
END AS Quantity

Related

get sum of all rows with id from main query

I need the sum of all positions from one year for every customer.
In the subquery i've hardcoded the customernumber (mark 1) but it needs to be another customernumber for every row.
The values in mark 2 are wrong.
SELECT CustomerNumber AS Kundennummer,
cont.CompanyName AS Firmenname,
(SELECT SUM(SumPositions) FROM OP_Invoices JOIN BAS_Customers ON OP_Invoices.Contact = BAS_Customers.Contact WHERE YEAR(DocumentDate) = 2018 AND BAS_Customers.CustomerNumber = '28673') AS '2018'
FROM BAS_Customers AS cust
JOIN BAS_Contacts AS cont
ON cust.Contact = cont.GUID
Thanks for your help!
If BAS_Customers and BAS_Contacts have a one-to-one relationship, then you should be able to use something like this:
SELECT BAS_Customers.CustomerNumber AS Kundennummer,
cont.CompanyName AS Firmenname,
SUM(SumPositions)
FROM OP_Invoices
JOIN BAS_Customers
ON OP_Invoices.Contact = BAS_Customers.Contact
JOIN BAS_Contacts AS cont
ON cust.Contact = cont.GUID
WHERE YEAR(DocumentDate) = 2018
GROUP BY BAS_Customers.CustomerNumber,
cont.CompanyName
Answering your follow up question in the comments:
SELECT BAS_Customers.CustomerNumber AS Kundennummer,
cont.CompanyName AS Firmenname,
SUM(case when YEAR(DocumentDate) = 2018 then SumPositions else 0 end) AS sum_2018,
SUM(case when YEAR(DocumentDate) = 2019 then SumPositions else 0 end) AS sum_2019
FROM OP_Invoices
JOIN BAS_Customers
ON OP_Invoices.Contact = BAS_Customers.Contact
JOIN BAS_Contacts AS cont
ON cust.Contact = cont.GUID
GROUP BY BAS_Customers.CustomerNumber,
cont.CompanyName

SQL Condition for sum

I have a sql statement with many inner join tables, as you can see below I have many conditional SUM statements , these sums are giving me wrong (very large) numbers as the inner join is repeating the same values in my source select pool. I was wondering id there is a way to limit these sum conditions lets say to EMPLIDs. The code is :
SELECT
A.EMPL_CTG,
B.DESCR AS PrName,
SUM(A.CURRENT_COMPRATE) AS SALARY_COST_BUDGET,
SUM(A.BUDGET_AMT) AS BUDGET_AMT,
SUM(A.BUDGET_AMT)*100/SUM(A.CURRENT_COMPRATE) AS MERIT_GOAL,
SUM(C.FACTOR_XSALARY) AS X_Programp,
SUM(A.FACTOR_XSALARY) AS X_Program,
COUNT(A.EMPLID) AS EMPL_CNT,
COUNT(D.EMPLID),
SUM(CASE WHEN A.PROMOTION_SECTION = 'Y' THEN 1 ELSE 0 END) AS PRMCNT,
SUM(CASE WHEN A.EXCEPT_IND = 'Y' THEN 1 ELSE 0 END) AS EXPCNT,
(SUM(CASE WHEN A.PROMOTION_SECTION = 'Y' THEN 1 ELSE 0 END)+SUM(CASE WHEN A.EXCEPT_IND = 'Y' THEN 1 ELSE 0 END))*100/(COUNT(A.EMPLID)) AS PEpercent
FROM
EMP_DTL A INNER JOIN EMPL_CTG_L1 B ON A.EMPL_CTG = B.EMPL_CTG
INNER JOIN
ECM_PRYR_VW C ON A.EMPLID=C.EMPLID
INNER JOIN ECM_INELIG D on D.EMPL_CTG=A.EMPL_CTG and D.YEAR=YEAR(getdate())
WHERE
A.YEAR=YEAR(getdate())
AND B.EFF_STATUS='A'
GROUP BY
A.EMPL_CTG,
B.DESCR
ORDER BY B.DESCR
I already tried moving D.YEAR=YEAR(getdate()) to the where clause. Any help would be greatly appereciated
The probable reason of your very large numbers is probably due to the result of Cartesian product of joining A -> B, A -> C and A -> D where tables C and D appear to have multiple records. So, just example... if A has 10 records, and C has 10 for each of the A records, you now have 10 * 10 records... Finally, join that to D table with 10 records, you now have 10 * 10 * 10 for each "A", thus your bloated answers.
Now, how to resolve. I have taken your "C" and "D" tables and "Pre-Aggregated" those counts based on the join column basis. This way, they will each have only 1 record with the total already computed at that level, joined back to A table and you lose your Cartesian issue.
Now, for table B, it appears that is a lookup table only and would only be a single record result anyhow.
SELECT
A.EMPL_CTG,
B.DESCR AS PrName,
SUM(A.CURRENT_COMPRATE) AS SALARY_COST_BUDGET,
SUM(A.BUDGET_AMT) AS BUDGET_AMT,
SUM(A.BUDGET_AMT)*100/SUM(A.CURRENT_COMPRATE) AS MERIT_GOAL,
PreAggC.X_Programp,
SUM(A.FACTOR_XSALARY) AS X_Program,
COUNT(A.EMPLID) AS EMPL_CNT,
PreAggD.DCount,
SUM(CASE WHEN A.PROMOTION_SECTION = 'Y' THEN 1 ELSE 0 END) AS PRMCNT,
SUM(CASE WHEN A.EXCEPT_IND = 'Y' THEN 1 ELSE 0 END) AS EXPCNT,
( SUM( CASE WHEN A.PROMOTION_SECTION = 'Y' THEN 1 ELSE 0 END
+ CASE WHEN A.EXCEPT_IND = 'Y' THEN 1 ELSE 0 END ) *
100 / COUNT(A.EMPLID) AS PEpercent
FROM
EMP_DTL A
INNER JOIN EMPL_CTG_L1 B
ON A.EMPL_CTG = B.EMPL_CTG
AND B.EFF_STATUS='A'
INNER JOIN ( select
C.EMPLID,
SUM(C.FACTOR_XSALARY) AS X_Programp
from
ECM_PRYR_VW C
group by
C.EMPLID ) PreAggC
ON A.EMPLID = PreAggC.EMPLID
INNER JOIN ( select
D.EMPLID,
COUNT(*) AS DCount
from
ECM_INELIG D
where
D.Year = YEAR( getdate())
group by
D.EMPLID ) PreAggD
ON A.EMPLID = PreAggD.EMPLID
WHERE
A.YEAR=YEAR(getdate())
GROUP BY
A.EMPL_CTG,
B.DESCR
ORDER BY
B.DESCR

Results of SQL grouping not as intended

Intro Details:
I have an issue with a query for Oracle SQL Developer using client 12c. I've researched several other questions on SO as well as searched Google for an answer to this, but ultimately the answers to all have been to include all columns without aggregate functions in the GROUP BY clause.
What I want is to get a single result for each category (PG.CAT) per year, week, and day (FD.YEAR, FD.WEEK, and FD.DT respectively). I want to sum the units, hours, errors (GE.QTY), and total hours. I also perform multiplication and division on two columns and join up to four other tables.
Query:
`SELECT
FD.YEAR,
FD.WEEK,
PG.DT,
PG.CAT,
SUM(PG.UNITS) AS UNITS,
SUM(PG.HOURS) AS HOURS,
PM.MTM,
PM.MTM * PG.HOURS AS ADJ_MTM,
(PG.UNITS / (PM.MTM * PG.HOURS)) AS PERC_STANDARD,
SUM(CASE WHEN GE.QTY IS NULL THEN 0 ELSE GE.QTY END) AS QTY,
SUM(WH.TOTALHOURS) AS TOTALHOURS
FROM
PROD_GUNS PG
INNER JOIN PROD_MTM PM
ON PG.CAT = PM.CATEGORY
AND PM.DEPTNO = '018'
AND PG.DT BETWEEN PM.START_DT AND PM.END_DT
INNER JOIN FISCAL_DATES_DAYS FD
ON PG.DT = FD.DT
LEFT OUTER JOIN PROD_GUNS_ERRORS GE
ON PG.EID = GE.EID
AND PG.DT = GE.DT
INNER JOIN WEEKLY_HOURS WH
ON FD.WEEK = WH.DT_WEEK
AND FD.YEAR = WH.DT_YEAR
AND PG.EID = WH.EEXX31
GROUP BY
FD.YEAR,
FD.WEEK,
PG.DT,
PG.CAT,
PM.MTM,
PM.MTM * PG.HOURS,
(PG.UNITS / ( PM.MTM * PG.HOURS))
HAVING
FD.YEAR = '2015'
AND FD.WEEK = '1'
AND PG.DT = '29-DEC-14'
AND PG.CAT = 'Picking'
ORDER BY
PG.DT;`
Actual Result:
2015 1 29-DEC-14 Picking 46 0.5 68 34 1.35294117647058823529411764705882352941 0 32.21
2015 1 29-DEC-14 Picking 831 7.72 68 524.96 1.58297775068576653459311185614142029869 0 29.35
Intended Result:
2015 1 20-Dec-14 Picking 877 8.22 68 558.96 1.21654501216545 0 61.59
Question:
With the aggregates and grouping that I have above, why would this not be giving me the intended result? Thank you all in advance for any guidance provided.
Try to SUM/AVG (depending on what you need) PM.MTM * PG.HOURS AS ADJ_MTM and (PG.UNITS / (PM.MTM * PG.HOURS)) AS PERC_STANDARD, not group by them:
SELECT
FD.YEAR,
FD.WEEK,
PG.DT,
PG.CAT,
SUM(PG.UNITS) AS UNITS,
SUM(PG.HOURS) AS HOURS,
PM.MTM,
SUM(PM.MTM * PG.HOURS )AS ADJ_MTM,
SUM((PG.UNITS / (PM.MTM * PG.HOURS))) AS PERC_STANDARD,
SUM(CASE WHEN GE.QTY IS NULL THEN 0 ELSE GE.QTY END) AS QTY,
SUM(WH.TOTALHOURS) AS TOTALHOURS
FROM
PROD_GUNS PG
INNER JOIN PROD_MTM PM
ON PG.CAT = PM.CATEGORY
AND PM.DEPTNO = '018'
AND PG.DT BETWEEN PM.START_DT AND PM.END_DT
INNER JOIN FISCAL_DATES_DAYS FD
ON PG.DT = FD.DT
LEFT OUTER JOIN PROD_GUNS_ERRORS GE
ON PG.EID = GE.EID
AND PG.DT = GE.DT
INNER JOIN WEEKLY_HOURS WH
ON FD.WEEK = WH.DT_WEEK
AND FD.YEAR = WH.DT_YEAR
AND PG.EID = WH.EEXX31
GROUP BY
FD.YEAR,
FD.WEEK,
PG.DT,
PG.CAT,
PM.MTM
HAVING
FD.YEAR = '2015'
AND FD.WEEK = '1'
AND PG.DT = '29-DEC-14'
AND PG.CAT = 'Picking'
ORDER BY
PG.DT;

To compute sum regarding to a constraint

I'm using PostgreSQL 8.4.
I have the following sql-query:
SELECT p.partner_id,
CASE WHEN pa.currency_id = 1 THEN SUM(amount) ELSE 0 END AS curUsdAmount,
CASE WHEN pa.currency_id = 2 THEN SUM(amount) ELSE 0 END AS curRubAmount,
CASE WHEN pa.currency_id = 3 THEN SUM(amount) ELSE 0 END AS curUahAmount
FROM public.player_account AS pa
JOIN player AS p ON p.id = pa.player_id
WHERE p.partner_id IN (819)
GROUP BY p.partner_id, pa.currency_id
The thing is that query does not what I expected. I realize that, but now I want to understand what exactly that query does. I mean, what SUM will be counted after the query executed. Could you clarify?
I think you have the conditions backwards in the query:
SELECT p.partner_id,
SUM(CASE WHEN pa.currency_id = 1 THEN amount ELSE 0 END) AS curUsdAmount,
SUM(CASE WHEN pa.currency_id = 2 THEN amount ELSE 0 END) AS curRubAmount,
SUM(CASE WHEN pa.currency_id = 3 THEN amount ELSE 0 END) AS curUahAmount
FROM public.player_account pa JOIN
player p
ON p.id = pa.player_id
WHERE p.partner_id IN (819)
GROUP BY p.partner_id;
Note that I also removed currency_id from the group by clause.
Maybe one row per (partner_id, currency_id) does the job. Faster and cleaner that way:
SELECT p.partner_id, pa.currency_id, sum(amount) AS sum_amount
FROM player_account pa
JOIN player p ON p.id = pa.player_id
WHERE p.partner_id = 819
AND pa.currency_id IN (1,2,3) -- may be redundant if there are not other
GROUP BY 1, 2;
If you need 1 row per partner_id, you are actually looking for "cross-tabulation" or a "pivot table". In Postgres use crosstab() from the additional module tablefunc , which is very fast. (Also available for the outdated version 8.4):
SELECT * FROM crosstab(
'SELECT p.partner_id, pa.currency_id, sum(amount)
FROM player_account pa
JOIN player p ON p.id = pa.player_id
WHERE p.partner_id = 819
AND pa.currency_id IN (1,2,3)
GROUP BY 1, 2
ORDER BY 1, 2'
,VALUES (1), (2), (3)'
) AS t (partner_id int, "curUsdAmount" numeric
, "curRubAmount" numeric
, "curUahAmount" numeric); -- guessing data types
Adapt to your actual data types.
Detailed explanation:
PostgreSQL Crosstab Query

How can I return 3 COUNT columns from the same table when JOIN with other tables as well?

I would like to know how I can return several COUNTs for the following:
I have 27 work sites, each site has an employee with a contract, I have wrote a script to return one actual column of data (Work sites, 27 in total), I then added a COUNT to count how many contracts/staff I have in each site. I have had to use 3 tables to get the data.
what I would like to do now is add two more columns, one that shows how many contracts I have "Under 35 hours" and one that shows how many I have "Over 35 hours"
This is what I have to return site names and total contracted hours:
SELECT
LOCATION.LocationName,
COUNT (EB_MINMAX_VIEW.UnitQuan) AS 'Total Contracts'
FROM
LOCATION
JOIN
eb_view on eb_view.locationcounter = location.locationcounter
JOIN
EB_MINMAX_VIEW on EB_MINMAX_VIEW.ebcounter = eb_view.ebcounter
GROUP BY
LOCATION.LocationName
Then if i want to return contacts under 35 hours then i have to write this:
SELECT
LOCATION.LocationName,
COUNT (EB_MINMAX_VIEW.UnitQuan) AS 'Total Contracts'
FROM
LOCATION
JOIN
eb_view on eb_view.locationcounter = location.locationcounter
JOIN
EB_MINMAX_VIEW on EB_MINMAX_VIEW.ebcounter = eb_view.ebcounter
WHERE
UnitQuan < 35
GROUP BY
LOCATION.LocationName
and this will give me the number of contracts less than 35 for all sites, but I want to include this in the final table i.e. site name, number of total contracts per site, number of contrast < 35 for all sites, and a column for number of contracts > 35 for each site.
Maybe this helps (I didn't test it):
SELECT s1.LocationName,
s1.TotalContracts AS cntAll,
s2.TotalContracts AS cntLess35,
s3.TotalContracts AS cntGreater35
FROM(SELECT LOCATION.LocationName,
COUNT(EB_MINMAX_VIEW.UnitQuan) TotalContracts
FROM LOCATION
JOIN eb_view ON eb_view.locationcounter = location.locationcounter
JOIN EB_MINMAX_VIEW on EB_MINMAX_VIEW.ebcounter = eb_view.ebcounter
GROUP
BY LOCATION.LocationName
) s1
LEFT
JOIN(SELECT LOCATION.LocationName,
COUNT(EB_MINMAX_VIEW.UnitQuan) TotalContracts
FROM LOCATION
JOIN eb_view ON eb_view.locationcounter = location.locationcounter
JOIN EB_MINMAX_VIEW on EB_MINMAX_VIEW.ebcounter = eb_view.ebcounter
WHERE UnitQuan < 35
GROUP
BY LOCATION.LocationName
) s2
ON s1.LocationName = s2.LocationName
LEFT
JOIN(SELECT LOCATION.LocationName,
COUNT(EB_MINMAX_VIEW.UnitQuan) TotalContracts
FROM LOCATION
JOIN eb_view ON eb_view.locationcounter = location.locationcounter
JOIN EB_MINMAX_VIEW on EB_MINMAX_VIEW.ebcounter = eb_view.ebcounter
WHERE UnitQuan > 35
GROUP
BY LOCATION.LocationName
) s3
ON s1.LocationName = s3.LocationName
Another alternative:
SELECT LOCATION.LocationName,
SUM(all),
SUM(less35),
SUM(greater35)
FROM(
SELECT LOCATION.LocationName,
1 AS all,
CASE WHEN UnitQuan < 35 THEN 1 ELSE 0 END less35,
CASE WHEN UnitQuan > 35 THEN 1 ELSE 0 END greater35
FROM LOCATION
JOIN eb_view ON eb_view.locationcounter = location.locationcounter
JOIN EB_MINMAX_VIEW on EB_MINMAX_VIEW.ebcounter = eb_view.ebcounter
)
GROUP BY LOCATION.LocationName
This is a simpler form of DirkNM's query:
SELECT l.LocationName,
count(*) AS all,
SUM(CASE WHEN ebmm.UnitQuan < 35 THEN 1 ELSE 0 END) as less35,
SUM(CASE WHEN ebmm.UnitQuan > 35 THEN 1 ELSE 0 END) greater35
FROM LOCATION JOIN
eb_view eb
ON eb.locationcounter = l.locationcounter JOIN
EB_MINMAX_VIEW ebmm
on ebmm.ebcounter = eb.ebcounter
GROUP BY l.LocationName