SQL Inner Join With Sum - mysql

I´m trying to sum a value with the inner join. There is 4 tables that i´m using the inner join on the another table.
Table 1 = mov_estoque
Table 2 = saidas
Table 3 = produtos
Table 4 = movimento
Table 5 = nf
On table 1, there is a column EMPENHO, data I wanna sum if the column PRODUTO is the same.
My code:
select m.DATA
,n.NOTA
,p.COD_PRODUTO
,p.DESCRICAO1
,p.FATOR_CA
,sum(m.EMPENHO) as Total
from mov_estoque as m
inner join saidas as s on m.origem = s.saida
inner join produtos as p on m.produto = p.produto
inner join movimento as t on m.origem = t.cod_operacao
inner join nf as n on s.saida = n.cod_operacao
where m.DATA>'2018-10-01'
and s.filial='3'
and p.tipo_prod='AC'
and (t.evento='21' or t.evento='35')
and m.tipo_origem ='S'
and s.cancelada='F'
and n.cancelada='F'
group by m.produto
order by m.data
But this code doesn´t work, I need the sum of empenho based on the produto column.
The output that I need:
http://prntscr.com/l9gk94
DATA NOTA COD_PRODUTO DESCRICAO1 EMPENHO FATOR_CA TOTAL
02/10/2018 00:00 164406 900809 SAL DO HIMALAIA FINO (GRANEL 1KG) -1 1 0

We can use an inline view to aggregate, to precompute, a total, and then do a join.
For example, we could write a query like this, to get sum of EMPHENHO grouped by produto.
SELECT sm.produto
, SUM(sm.EMPENHO) AS sum_empenho
FROM mov_estoque sm
WHERE sm.DATA > '2018-10-01'
AND sm.tipo_origem = 'S'
GROUP
BY sm.produto
The specification for the total is unclear in the question. This is likely not the total that is desired. But this does demonstrate how we could get a sum, a single row for each value of produto.
Assuming that the rest of the query returns the detail rows that we want returned, that is, of we leave off the GROUP BY clause and the SUM aggregate:
SELECT m.DATA
, n.NOTA
, p.COD_PRODUTO
, p.DESCRICAO1
, p.FATOR_CA
FROM mov_estoque m
JOIN saidas as s on m.origem = s.saida
JOIN produtos as p on m.produto = p.produto
JOIN movimento as t on m.origem = t.cod_operacao
JOIN nf as n on s.saida = n.cod_operacao
WHERE m.DATA > '2018-10-01'
AND s.filial = '3'
AND p.tipo_prod = 'AC'
AND (t.evento='21' OR t.evento='35')
AND m.tipo_origem = 'S'
AND s.cancelada='F'
AND n.cancelada='F'
ORDER BY m.data
If that gets us the rows we want to return, and we just want to add a "total" column.
Then we could use the first query as a rowsource. Wrap it in parens and reference it the FROM clause as an inline view, with appropriate join conditions, and reference the column with the pre-aggregated total in the SELECT list. Something like this:
SELECT m.DATA
, n.NOTA
, p.COD_PRODUTO
, p.DESCRICAO1
, p.FATOR_CA
, s.sum_empenho AS total
FROM mov_estoque m
JOIN saidas as s on m.origem = s.saida
JOIN produtos as p on m.produto = p.produto
JOIN movimento as t on m.origem = t.cod_operacao
JOIN nf as n on s.saida = n.cod_operacao
JOIN ( SELECT sm.produto
, SUM(sm.EMPENHO) AS sum_empenho
FROM mov_estoque sm
WHERE sm.DATA > '2018-10-01'
AND sm.tipo_origem = 'S'
GROUP
BY sm.produto
) s
ON s.produto = m.produto
WHERE m.DATA > '2018-10-01'
AND s.filial = '3'
AND p.tipo_prod = 'AC'
AND (t.evento='21' OR t.evento='35')
AND m.tipo_origem = 'S'
AND s.cancelada='F'
AND n.cancelada='F'
ORDER BY m.data

Related

Sql trouble with coalesce() not working propely

i have a query and i'm having trouble to change the name of the last row of columb name to 'TOTAL'. The result gives me the same name of the row above the last row.
Here's my query:
SELECT COALESCE(ticket_types.name,'TOTAL') AS name,
COUNT(1) AS quantity
FROM tr_logs
LEFT JOIN tickets ON tr_logs.value = tickets.id
LEFT JOIN ticket_types ON tickets.ticket_type_id = ticket_types.id
LEFT JOIN transactions ON tr_logs.transaction_id = transactions.id
LEFT JOIN tr_fields_data AS tfd_shipping ON tfd_shipping.transaction_id = transactions.id
WHERE type = 'ADDITEM'
AND transactions.event_id = '46'
AND DATE(tr_logs.created_date)
BETWEEN '2017-03-26' AND '2017-05-24'
AND tfd_shipping.data IN ('0','570','571','771')
AND name IS NOT NULL
GROUP BY ticket_types.id WITH ROLLUP
The result looks like this:
name quantity
premium 56
outlaw 6
outlaw 62
Last row name from rollup is not null.... I need it to be TOTAL and not outlaw
Thanks
You haven't changed the name to TOTAL at all: you've changed the name of the column to name, and you've told it to replace any null values with TOTAL.
If you want to change the name of ticket_types.name to total, you just want
SELECT ticket_types.name AS total ...
(But it would be weird to rename something called name to total, so perhaps you need to clarify your requirements a little.)
This may or not be related to your observed problem, but the WHERE and GROUP BY clauses turn all the outer joins into inner joins. You should simplify the query to:
SELECT COALESCE(tt.name, 'TOTAL') AS name, COUNT(1) AS quantity
FROM tr_logs l JOIN
tickets
ON l.value = t.id JOIN
ticket_types tt
ON t.ticket_type_id = tt.id JOIN
transactions tr
ON l.transaction_id = tr.id JOIN
tr_fields_data fd
ON fd.transaction_id = tr.id
WHERE type = 'ADDITEM' AND
tr.event_id = '46' AND
DATE(l.created_date) BETWEEN '2017-03-26' AND '2017-05-24' AND
fd.data IN ('0', '570', '571', '771') AND
tt.name IS NOT NULL
GROUP BY tt.id WITH ROLLUP
Thanks to Gordon Linoff I have figure out my problem.
The name of the last row was never null beacause i GROUP BY with a different attribute.
Here's the solution.
SELECT COALESCE(tckn,'TOTAL') AS name, quantity FROM
(SELECT tt.name AS tckn, COUNT(1) AS quantity
FROM tr_logs AS l
LEFT JOIN tickets AS t ON l.value = t.id
LEFT JOIN ticket_types AS tt ON t.ticket_type_id = tt.id
LEFT JOIN transactions AS tr ON l.transaction_id = tr.id
LEFT JOIN tr_fields_data AS tfd ON tfd.transaction_id = tr.id
WHERE type = 'ADDITEM'
AND tr.event_id = '46'
AND DATE(l.created_date)
BETWEEN '2017-03-26' AND '2017-05-24'
AND tfd.data IN ('0','570','571','771')
GROUP BY tckn WITH ROLLUP) as sum;

MYSQL update a column with a subtract in a inner join

I want to update column 'pagadas' from 'remisiones' with a calculated value from another 2 tables. My problem is I´m not be able to write the subtract into the inner join.
I´ve got this:
UPDATE remisiones AS r
INNER JOIN
(
SELECT remi, SUM(cantidad*precio) AS 'total'
FROM detalleremi
GROUP BY remi
)
AS d
ON r.id = d.remi
SET pagadas = 's'
WHERE d.total = 250000
This works too:
UPDATE remisiones AS r
INNER JOIN
(
SELECT remisionId, coalesce(SUM(cantidadp), 0) 'pagos'
FROM pagos
GROUP BY remisionId
)
AS d
ON r.id = d.remisionId
SET pagadas = 's'
WHERE d.pagos = 250000
But how can I subtract total - pagos ?
SELECT remi, SUM(cantidad*precio)
FROM detalleremi
GROUP BY remi -
SELECT remisionId, coalesce(SUM(cantidadp), 0)
FROM pagos
GROUP BY remisionId AS deuda
and set as:
SET pagadas = 's'
WHERE x.deuda = 0
Is this what you want?
UPDATE remisiones r INNER JOIN
(SELECT remi, SUM(cantidad*precio) as total
FROM detalleremi
GROUP BY remi
) d
ON r.id = d.remi INNER JOIN
(SELECT remisionId, coalesce(SUM(cantidadp), 0) as pagos
FROM pagos
GROUP BY remisionId
) p
ON r.id = p.remisionId
SET pagadas = 's'
WHERE d.total = p.pagos

selecting row with highest value and a join

Ho can i only fetch the rows with the highest cvID value?
current code
SELECT
CollectionVersionBlocks.cID,
CollectionVersionBlocks.cbDisplayOrder,
CollectionVersionBlocks.cvID,
btContentLocal.bID,
btContentLocal.content
FROM
CollectionVersionBlocks
INNER JOIN btContentLocal
ON CollectionVersionBlocks.bID = btContentLocal.bID
WHERE (CollectionVersionBlocks.cID = 259)
AND CollectionVersionBlocks.isOriginal = 1
AND CollectionVersionBlocks.arHandle = 'main'
AND btContentLocal.content != ''
I want to get the row at the bottom (where the cvID value is 10).
This is a test statement for a bigger result set -
I will eventually need a set of results from perset cIDs (CollectionVersionBlocks.cID = 259 OR CollectionVersionBlocks.cID = 260... upto 800)
updated screenshots
1) too few results
2) un grouped results
To get the highest row per group (from your question i assume cID as a single group) you can do so by using a self join on the maxima of your desired column by using additional condition in in your third join i.e ON(c.cID=cc.cID AND c.cvID=cc.cvID)
SELECT
c.cID,
c.cbDisplayOrder,
c.cvID,
b.bID,
b.content
FROM
CollectionVersionBlocks c
INNER JOIN btContentLocal b
ON (c.bID = b.bID)
INNER JOIN
(SELECT cID, MAX(cvID) cvID FROM CollectionVersionBlocks GROUP BY cID) cc
ON(c.cID=cc.cID AND c.cvID=cc.cvID)
WHERE (c.cID = 259)
AND c.isOriginal = 1
AND c.arHandle = 'main'
AND b.content != ''
and for multiple groups you can just use WHERE c.cID IN(259,....800)
Try below Query:
SELECT CollectionVersionBlocks.cID,CollectionVersionBlocks.cbDisplayOrder, CollectionVersionBlocks.cvID , btContentLocal.bID , btContentLocal.content
FROM CollectionVersionBlocks
INNER JOIN btContentLocal
ON CollectionVersionBlocks.bID=btContentLocal.bID
WHERE (CollectionVersionBlocks.cID = 259)
AND CollectionVersionBlocks.isOriginal=1 AND CollectionVersionBlocks.arHandle ='main' AND btContentLocal.content !='' and CollectionVersionBlocks.cID in
(
SELECT Max(CollectionVersionBlocks.cID)
FROM CollectionVersionBlocks
INNER JOIN btContentLocal
ON CollectionVersionBlocks.bID=btContentLocal.bID
WHERE (CollectionVersionBlocks.cID = 259)
AND CollectionVersionBlocks.isOriginal=1 AND CollectionVersionBlocks.arHandle ='main' AND btContentLocal.content !='' )

Trying to add one last SUM() column to my query in SQL Server 2008

I have the first query which is producing correct results. What I need is I need to add the sum of values as a last column grouped by surveyid. I can't insert Sum(c.value) into the first query because it is an aggregate function. I have the correct query as my second query below. I know there's pivot functionality but not sure if it can be used here. I do realize that there will be repetition but that's okay.
'first query
SELECT
A.PATIENTID, B.STUDENTNUMBER, c.surveyid,
convert(varchar, A.CreatedDate, 107),
C.QuestionID, C.Value, D.Question
FROM
dbo.Survey A, dbo.Patient B, [dbo].[SurveyQuestionAnswer] C, [dbo].[LookupQuestions] D
WHERE
A.PATIENTID = B.ID
and c.SurveyID = A.ID
and c.QuestionID = d.ID
and c.questionid <> 10
ORDER BY
A.PATIENTID
'second query
select
c.surveyid,SUM(c.value) as scores
from
dbo.SurveyQuestionAnswer c
group by
c.SurveyID
order by
SurveyID '---not important
You can use SUM if you add the OVER clause. In this case:
SELECT
A.PATIENTID, B.STUDENTNUMBER, c.surveyid,
convert(varchar, A.CreatedDate, 107),
C.QuestionID, C.Value, D.Question,
SUM(c.Value) OVER(PARTITION BY c.surveyid) scores
FROM
dbo.Survey A
INNER JOIN dbo.Patient B
ON A.PATIENTID = B.ID
INNER JOIN [dbo].[SurveyQuestionAnswer] C
ON c.SurveyID = A.ID
INNER JOIN [dbo].[LookupQuestions] D
ON c.QuestionID = d.ID
WHERE
c.questionid <> 10
ORDER BY
A.PATIENTID
You could use something like this:
SELECT
s.PATIENTID, p.STUDENTNUMBER, sqa.surveyid,
CONVERT(varchar, s.CreatedDate, 107),
sqa.QuestionID, sqa.Value, lq.Question,
Scores = (SELECT SUM(Value) FROM dbo.SurveyQuestionAnswer s2 WHERE s2.SurveyID = s.ID)
FROM
dbo.Survey s
INNER JOIN
dbo.Patient p ON s.PatientID = p.ID
INNER JOIN
[dbo].[SurveyQuestionAnswer] sqa ON sqa.SurveyID = s.ID
INNER JOIN
[dbo].[LookupQuestions] lq ON sqa.QuestionID = lq.ID
WHERE
sqa.questionid <> 10
ORDER BY
s.PATIENTID
By having a subquery with the SUM(...) you should be able to get that sum as a single value and you don't need to use any grouping function

How can I make more than one select queries in single select query.

I have to write a query where, I need to fetch records for last week, last month, and for all.
For this problem I wrote 3 diffrent queries (for last week, for last month and for all)
For Weekly Info :-
SELECT bu.brand_name AS 'Brand_Name',COUNT(s.unique) AS '# Item Sold',SUM(s.price) AS 'Total_Price'
FROM item_details s
LEFT JOIN sales_order o ON s.fk_sales_order = o.id_sales_order
LEFT JOIN customer_info AS c ON o.fk_customer_id = c.id_customer
LEFT JOIN simple_details cc ON s.unique = cc.unique
LEFT JOIN config_details cf ON cc.fk_config_id = cf.config_id
LEFT JOIN brand_details cb ON cf.fk_brand_id = cb.brand_id
LEFT JOIN category_details ctc ON cf.fk_category_id = ctc.category_id
LEFT JOIN gender_details g ON cf.fk_gender_id = g.gender_id
LEFT JOIN buyers AS bu ON bu.brand_name = cb.name AND bu.category_name = ctc.name AND bu.gender = g.name
WHERE bu.buyers = 'xyz' AND DATE_FORMAT(o.created_date,'%Y-%m-%d') >= #weekstartdate AND DATE_FORMAT(o.created_date,'%Y-%m-%d') <= #weekenddate
GROUP BY bu.brand_name
For Monthly Info :-
SELECT bu.brand_name AS 'Brand_Name',COUNT(s.unique) AS '# Item Sold',SUM(s.price) AS 'Total_Price'
FROM item_details s
LEFT JOIN sales_order o ON s.fk_sales_order = o.id_sales_order
LEFT JOIN customer_info AS c ON o.fk_customer_id = c.id_customer
LEFT JOIN simple_details cc ON s.unique = cc.unique
LEFT JOIN config_details cf ON cc.fk_config_id = cf.config_id
LEFT JOIN brand_details cb ON cf.fk_brand_id = cb.brand_id
LEFT JOIN category_details ctc ON cf.fk_category_id = ctc.category_id
LEFT JOIN gender_details g ON cf.fk_gender_id = g.gender_id
LEFT JOIN buyers AS bu ON bu.brand_name = cb.name AND bu.category_name = ctc.name AND bu.gender = g.name
WHERE bu.buyers = 'xyz' AND DATE_FORMAT(o.created_date,'%Y-%m-%d') >= #monthstartdate AND DATE_FORMAT(o.created_date,'%Y-%m-%d') <= #monthenddate
GROUP BY bu.brand_name
For All Records :-
SELECT bu.brand_name AS 'Brand_Name',COUNT(s.unique) AS '# Item Sold',SUM(s.price) AS 'Total_Price'
FROM item_details s
LEFT JOIN sales_order o ON s.fk_sales_order = o.id_sales_order
LEFT JOIN customer_info AS c ON o.fk_customer_id = c.id_customer
LEFT JOIN simple_details cc ON s.unique = cc.unique
LEFT JOIN config_details cf ON cc.fk_config_id = cf.config_id
LEFT JOIN brand_details cb ON cf.fk_brand_id = cb.brand_id
LEFT JOIN category_details ctc ON cf.fk_category_id = ctc.category_id
LEFT JOIN gender_details g ON cf.fk_gender_id = g.gender_id
LEFT JOIN buyers AS bu ON bu.brand_name = cb.name AND bu.category_name = ctc.name AND bu.gender = g.name
WHERE bu.buyers = 'xyz'
GROUP BY bu.brand_name
and these are working fine (giving currect output).
But problem is that, I have to merge these three queries in single one.
Where output should be as
Brand name, item_sold(week), total_price(week),item_sold(month), total_price(month),item_sold(all), total_price(all)
How can I write this query?
Without looking deep into your code, the obvious solution would be
SELECT
all.brand_name
pw.items_sold items_sold_week
pw.total_price total_price_week
pm.items_sold items_sold_month
pm.total_price total_price_month
all.items_sold items_sold_all
all.total_price total_price_all
FROM
(your all-time select) all
JOIN (your per-month select) pm ON all.brand_name = pm.brand_name
JOIN (your per-week select) pw ON all.brand_name = pw.brand_name
Though you probably should rethink your entire approach and make sure whether you really want that kind of logic in a DB layer or it is better to be in your application.
You could use case to limit aggregates to a subset of rows:
select bu.brand_name
, count(case when date_format(o.created_date,'%Y-%m-%d') >= #weekstartdate
and date_format(o.created_date,'%Y-%m-%d') <= #weekenddate
then 1 end) as '# Item Sold Week'
, sum(case when date_format(o.created_date,'%Y-%m-%d') >= #weekstartdate
and date_format(o.created_date,'%Y-%m-%d') <= #weekenddate
then s.price end) as 'Total_Price Week'
, count(case when date_format(o.created_date,'%Y-%m-%d') >= #monthstartdate
and date_format(o.created_date,'%Y-%m-%d') <= #monthstartdate
then 1 end) as '# Item Sold Month'
, ...
If all three selects uses the same fields in the results, you can UNION them:
SELECT *
FROM (SELECT 1) AS a
UNION (SELECT 2) AS b
UNION (SELECT 3) AS c
If you need to tell week/mon/all records from each other - just add constant field containing "week" or "mon"
You cam use the UNION.keyword between the queries to bundle them.together BUT tje column types and sequence must be the same in all queries. You could add an identifier to each set