How to Combine 2 rows with different values in different column - mysql

I want to combine 2 rows with the same date but have different values ​​in different columns. like this:
tgl qty_NEW MIO M3 125 CW-OTR qty_NEW-SOUL-GT-125-OTR
---------- ------------------------- -------------------------
2016-05-01 0 0
2016-05-02 0 0
2016-05-05 0 0
2016-05-09 0 0
2016-05-10 2 0
2016-05-10 0 1
There is the same 2016-05-10 with the values ​​are 2 - 0, and 0 - 1.
What I want is like this:
tgl qty_NEW MIO M3 125 CW-OTR qty_NEW-SOUL-GT-125-OTR
---------- ------------------------- -------------------------
2016-05-01 0 0
2016-05-02 0 0
2016-05-05 0 0
2016-05-09 0 0
2016-05-10 2 1
And the query I use is like this:
SELECT DISTINCT DATE(m.tgl_fj) AS tgl ,
CASE brg.nama_brg WHEN 'NEW MIO M3 125 CW-OTR' THEN SUM(d.qty) ELSE '0' END AS 'qty_NEW MIO M3 125 CW-OTR' ,
CASE brg.nama_brg WHEN 'NEW-SOUL-GT-125-OTR' THEN SUM(d.qty) ELSE '0' END AS 'qty_NEW-SOUL-GT-125-OTR'
FROM tb_mt_fj m
LEFT OUTER JOIN tb_dt_fj_brg d
ON m.ucode_fj=d.ucode_fj
LEFT OUTER JOIN tb_m_brg brg
ON d.ucode_brg=brg.ucode_brg
LEFT OUTER JOIN tb_m_grp_brg grp
ON brg.ucode_grp_brg=grp.ucode_grp_brg
WHERE brg.ucode_grp_brg='11040000000089' AND MONTH(m.tgl_fj)=MONTH(NOW())
GROUP BY DATE(m.tgl_fj), brg.nama_brg
ORDER BY DATE(m.tgl_fj)
So, how to make the query result the same as I want?

This query should do it
select tgl, sum(qty_NEW MIO M3 125 CW-OTR) as `left`, sum(qty_NEW-SOUL-GT-125-OTR) as `right` from `table` group by tgl

Related

Show mysql result of one column in different columns

I'm new to mysql and currently stuggeling with a little weird problem,
I am faced with a list with three rows:
Customernr Type Amount
------------------------------
111 A 10
111 B 5
111 C 21
222 B 12
333 A 20
333 C 14
I need to format the output like:
Customernr A B C
----------------------------------
111 10 5 21
222 0 12 0
333 20 0 14
I have tried it with multiple "if" clauses:
SELECT distinct `Customernr`,
IF(`Type`='A' ,`Amount`, 0) as A,
IF(`Type`='B' ,`Amount`, 0) as B,
IF(`Type`='C' ,`Amount`, 0) as C,
FROM `database`
The result is:
Customernr A B C
----------------------------------
111 10 0 0
111 0 5 0
111 0 0 21
222 0 12 0
333 20 0 0
333 0 0 14
If I add a group by Customern
the result will display only the first value
Customernr A B C
----------------------------------
111 10 0 0
222 0 0 0
333 20 0 0
Maybe my approach is totally wrong but I hope you can understand the problem, not all customers do not have all types but I need to display every customer in one row including all his amounts of types even if the customer does not have all types.
I have searched through stackoverflow and as this is my first post I hop I am doing everything right.
Any help appreciated.
Try this
SELECT Customernr,sum(temp.A) as A,sum(temp.B) as B,sum(temp.C) as C from(
SELECT `Customernr`,
IF(`Type`='A' ,(SELECT SUM(AMOUNT) FROM test_db td2 WHERE TYPE='A' AND td2.Customernr=td.Customernr ), 0) as A,
IF(`Type`='B' ,(SELECT SUM(AMOUNT) FROM test_db td2 WHERE TYPE='B' AND td2.Customernr=td.Customernr ), 0) as B,
IF(`Type`='C' ,(SELECT SUM(AMOUNT) FROM test_db td2 WHERE TYPE='C' AND td2.Customernr=td.Customernr ), 0) as C
FROM test_db td ) as temp GROUP BY Customernr
I got the result
111 10 5 21
222 0 12 0
333 20 0 14

SQL Join Inventory Count Table to Date table

I have a running inventory table of different products that records the inventory count after every transaction. Transactions do not happen every day, so the table does not have a running daily count.
I need to have all dates listed for each product so that I can sum and average the counts over a period of time.
inventory
DATE ID Qty Count
2014-05-13 123 12 12
2014-05-19 123 -1 11
2014-05-28 123 -1 10
2014-05-29 123 -3 7
2014-05-10 124 5 5
2014-05-15 124 -1 4
2014-05-21 124 -1 3
2014-05-23 124 -3 0
I have a table that includes dates for a Join, but I am not sure how to make the missing dates join over multiple products.
I need the query as follows. It needs to to return the counts over the a period selected, but also include dates inbetween.
DATE ID Qty Count
2013-05-01 123 0 0
2013-05-02 123 0 0
2013-05-03 123 0 0
2013-05-04 123 0 0
2013-05-05 123 0 0
2013-05-06 123 0 0
2013-05-07 123 0 0
2013-05-08 123 0 0
2013-05-09 123 0 0
2013-05-10 123 0 0
2013-05-11 123 0 0
2013-05-12 123 0 0
2014-05-13 123 12 12
2013-05-14 123 0 12
2013-05-15 123 0 12
2013-05-16 123 0 12
2013-05-17 123 0 12
2013-05-18 123 0 12
2014-05-19 123 -1 11
2013-05-20 123 0 11
2013-05-21 123 0 11
2013-05-22 123 0 11
2013-05-23 123 0 11
2013-05-24 123 0 11
2013-05-25 123 0 11
2013-05-26 123 0 11
2013-05-27 123 0 11
2014-05-28 123 -1 10
2014-05-29 123 -3 7
2013-05-30 123 0 7
2013-05-31 123 0 7
2013-05-01 124 0 0
2013-05-02 124 0 0
2013-05-03 124 0 0
2013-05-04 124 0 0
2013-05-05 124 0 0
2013-05-06 124 0 0
2013-05-07 124 0 0
2013-05-08 124 0 0
2013-05-09 124 0 0
2014-05-10 124 5 5
2014-05-11 124 0 5
2014-05-12 124 0 5
2014-05-13 124 0 5
2014-05-14 124 0 5
2014-05-15 124 -1 4
2014-05-16 124 0 4
2014-05-17 124 0 4
2014-05-18 124 0 4
2014-05-19 124 0 4
2014-05-20 124 0 4
2014-05-21 124 -1 3
2014-05-22 124 0 3
2014-05-23 124 -3 0
2014-05-24 124 0 0
2014-05-25 124 0 0
2014-05-26 124 0 0
2014-05-27 124 0 0
2014-05-28 124 0 0
2014-05-29 124 0 0
2014-05-30 124 0 0
2014-05-31 124 0 0
Use inv join inv to build up at least 31 rows and construct a table of 31 days. Then join the ids, and finally the original table.
select a.d, a.id, a.qty,
if(a.id=#lastid, #count:=#count+a.qty, #count:=a.count) `count`,
#lastid:=a.id _lastid
from (
select a.d, b.id, ifnull(c.qty, 0) qty, ifnull(c.count, 0) `count`
from (
select adddate('2014-05-01', #row) d, #row:=#row+1 i
from inv a
join inv b
join (select #row := 0) c
limit 31) a
join (
select distinct id
from inv) b
left join inv c on a.d = c.date and b.id = c.id
order by b.id, a.d) a
join (select #count := 0, #lastid := 0) b;
fiddle
Here are the steps needed:
Get all dates between the two given dates.
Get the initial stock per ID. This is: get the first date on or after the given start date for that ID, read this record's stock and subtract its transaction quantity.
For every date get the previous stock. If there is a record for this date, then add its transaction quantity and compare the result with its stock quantity. Throw an error if values don't match. (This is because you store data redundantly; a record's quantity must equal the quantity of the previous record plus its own transaction quantity. But data can always be inconsistent, so better check it.) Show the new stock and the difference to the previous stock.
All this would typically be achieved with a recursive CTE for the dates, a derived table for all initial stocks at best using a KEEP DENSE_RANK function, and the LAG function to look into the previous record.
MySQL doesn't support recursive CTEs - or CTEs at all for that matter. You can emulate this with a big enough table and a variable.
MySQL doesn't support the KEEP DENSE_RANK function. You can work with another derived table instead to find the minimum date per ID first.
MySQL doesn't support the LAG function. You can work with a variable in MySQL instead.
Having said this, I suggest to use a programming language instead (Java, C#, PHP, whatever). You would just select the raw data with SQL, use a loop and simply do all processiong on a per record base. This is much more convenient (and readable) than building a very complex query that does all that's needed. You can do this in SQL, even MySQL; I just don't recommend it.
The SQL I ended up using to resolve this question used a combination of #Fabricators answer (which really was a correct answer) and my edits.
I ended up using an existing table to create the date rows instead of a cross join. The cross join had poor performance for how many products I was working with.
SELECT
POSTDATE,
IF(#PROD_ID = PRODUCT_ID, #NEW := 0, #NEW := 1) AS New_Product,
(#PROD_ID := PRODUCT_ID) AS PRODUCT_ID,
QUANTITY,
IF(#NEW = 1, #INVENTORY := QUANTITY, #INVENTORY := #INVENTORY+QUANTITY) AS 'Count'
FROM (
(
SELECT
POSTDATE,
PRODUCT_ID,
QUANTITY
FROM
inventory
)
UNION ALL
(
SELECT
dateslist_sub.TransDate AS POSTDATE,
productlist_sub.PRODUCT_ID,
0 AS QUANTITY,
FROM
(
SELECT
TransDate
FROM
(
SELECT
adddate('2013-05-01', #row) AS TransDate,
#row:=#row+1 i
FROM
any_table,
(SELECT #row := 0) row
) datestable
WHERE
TransDate <= CURDATE()
) dateslist_sub
cross join (
SELECT
PRODUCT_ID
FROM
products_table
ORDER BY
PRODUCT_ID ASC
) productlist_sub
ORDER BY
productlist_sub.PRODUCT_ID ASC,
dateslist_sub.TransDate ASC
)
ORDER BY
PRODUCT_ID ASC,
POSTDATE ASC
) daily_rows_sub

Rearrange MySQL table from each month

This is my target table
retail_id month tgt_volume product_type
1 2013-11-01 2 Bar
2 2013-10-01 1 Touch
3 2013-09-01 1 Bar
4 2013-10-01 5 Smart
5 2013-10-01 8 Bar
3 2013-08-01 2 Smart
2 2013-08-01 5 Bar
3 2013-07-01 7 Bar
3 2013-07-01 2 Smart
I need this format
retail_id bar smart touch total month
1 2 0 0 2 2013-11-01
2 0 0 1 1 2013-10-01
2 5 0 0 5 2013-08-01
3 1 0 0 1 2013-09-01
3 0 2 0 2 2013-08-01
3 7 2 0 9 2013-07-01
4 0 5 0 5 2013-08-01
5 8 0 0 8 2013-10-01
So I want to retrieve every months total target and each product type total for each retail_id. I was trying a query which count every product_type but not count each month. How can I do this to make above format.. my test query is(without month count)
SELECT DISTINCT t.retail_id,bar_vol.bar,smart_vol.smart,touch_vol.touch,total.total,t.month FROM targets t
LEFT JOIN
(SELECT SUM(tgt_volume) AS bar,retail_id FROM targets t1 WHERE t1.product_type='Bar' GROUP BY retail_id) AS bar_vol
ON t.retail_id=bar_vol.retail_id
LEFT JOIN
(SELECT SUM(tgt_volume) AS smart,retail_id FROM targets t2 WHERE t2.product_type='Smart' GROUP BY retail_id) AS smart_vol
ON t.retail_id=smart_vol.retail_id
LEFT JOIN
(SELECT SUM(tgt_volume) AS touch,retail_id FROM targets t3 WHERE t3.product_type='Touch' GROUP BY retail_id) AS touch_vol
ON t.retail_id=touch_vol.retail_id
LEFT JOIN
(SELECT SUM(tgt_volume) AS total,retail_id FROM targets t4 GROUP BY retail_id) AS total
ON t.retail_id=total.retail_id
You can use a CASE statement inside an aggregate function to achieve this:
SELECT Retail_ID,
SUM(CASE WHEN product_Type = 'Bar' THEN tgt_Volume ELSE 0 END) AS Bar,
SUM(CASE WHEN product_Type = 'smart' THEN tgt_Volume ELSE 0 END) AS Smart,
SUM(CASE WHEN product_Type = 'Touch' THEN tgt_Volume ELSE 0 END) AS Touch,
SUM(tgt_Volume) AS Total,
Month
FROM targets
GROUP BY RetailId, Month;
Example on SQL Fiddle

Join table in order to create field with data from different tables

I need to update a field named "tipos" in a table named azz_properties with values from other tables named azz_locality (field name is "name") and azz_category (field name is also "name"), using a word to separate those values, the word "in". Substantially I need to create a mini-description phrase, like "Property Category in Property Locality", Ex. House in Rome.
Also, I need to update the value only if it is empty.
I tried the following code but i receive "0 lines affected"
update azz_properties p join
azz_locality l
on p.id = l.id join
azz_category c
on p.id = c.id
set p.tipos = concat(c.name, ' in ', l.name);
Anyone can help me please? What am I doing wrong?
below are some lines from each table, I tried to make this visible in a good way but this is the best I could do, sorry for it...:
Table azz_category
id name alias parent published ordering
17 Apartamentos apartamentos 0 1 0
18 Casas casas 0 1 1
19 Casas em condominios casas-em-condominios 0 1 2
20 Coberturas coberturas 0 1 3
Table azz_locality
id parent mid zipcode name alias published ordering checked_out checked_out_time
1 1 0 0 Abraão abraao 1 0 0 0000-00-00 00:00:00
2 1 0 0 Armação armacao 1 0 0 0000-00-00 00:00:00
3 1 0 0 Agronômica agronomica 1 0 0 0000-00-00 00:00:00
5 1 0 0 Bairro de Fatima bairro-de-fatima 1 0 0 0000-00-00 00:00:00
6 1 0 0 Balneário Estreito balneario-estreito 1 0 0 0000-00-00 00:00:00
7 1 0 0 Barra da Lagoa barra-da-lagoa 1 0 0 0000-00-00 00:00:00
9 1 0 0 Beira Mar beira-mar 1 0 0 0000-00-00 00:00:00
10 1 0 0 Bela Vista bela-vista 1 0 0 0000-00-00 00:00:00
168 19 0 0 Siriú siriu 0 0 0 0000-00-00 00:00:00
This is azz_properties, where category id is "cid" field and locality id is "lid"
id name name_tipos name_barrios alias parent agent_id agent ref type cid lid sid cyid postcode address description text text_es text_en text_barrios tipos price published use_booking ordering panoramic video lat lng available featured years bedrooms bathrooms garage area covered_area hits listdate refresh_time checked_out checked_out_time
2920 Vendo Apartamento... Vendo Apartamento... vendo-apartamento... 0 62 A3044 62 17 3 1 1 Rua Silveira Agenciamento... <p>Apartamento ... 360000.00 1 0 0 NULL 0.000000 0.000000 0 0 2012.01.01.05110 3 2 1 105 90 231 2013-05-03 2013-05-03 00:00:00 0 0000-00-00 00:00:00
Seems like what you need, given the data, is:
update azz_properties p join
azz_locality l
on p.lid = l.id join
azz_category c
on p.cid = c.id
set p.tipos = concat(c.name, ' in ', l.name);

access query needed

I am looking for an access query, but a sql server 2008 could be sufficient as I can use a passthrough feature in access.
My data looks like this .
--------------------------------------------------------------
id nameid name score diff include
--------------------------------------------------------------
1 0001 SO 100 0 0
2 0001 SO 100 0 0
3 0001 SO 100 0 0
4 0001 SO 100 0 0
5 0001 SO 100 0 0
6 0001 SO 100 0 0
7 0002 MO 10 0 0
8 0002 MO 18 0 1
9 0002 MO 20 0 0
10 0002 MO 14 0 0
11 0002 MO 100 0 0
11 0002 MO 100 0 0
12 0003 MA 10 0 0
13 0003 MA 18 0 1
14 0003 MA 20 0 0
15 0003 MA 14 0 0
16 0003 MA 100 0 1
17 0003 MA 100 0 0
Now what i want is to go through each row and only select the rows where include = 1. THIS IS EASY however ,I don't want the entire row.. I want to select the "group". The group can be identified by the nameid (or name).
So for the above I want the following result:
--------------------------------------------------------------
id nameid name score diff include
--------------------------------------------------------------
7 0002 MO 10 0 0
8 0002 MO 18 0 1
9 0002 MO 20 0 0
10 0002 MO 14 0 0
11 0002 MO 100 0 0
11 0002 MO 100 0 0
12 0003 MA 10 0 0
13 0003 MA 18 0 1
14 0003 MA 20 0 0
15 0003 MA 14 0 0
16 0003 MA 100 0 1
17 0003 MA 100 0 0
Ask your table for row with include = 1.
Then join again with the table to have all the rows corresponding to the first query's nameid :
SELECT DISTINCT m.*
FROM myTable m
INNER JOIN myTable m2
ON m.nameid = m2.nameid
AND m2.include = 1
A join query will work better than an 'in' query for big amount of datas. You still need an index on the field 'nameid', and on 'include' could not hurt too.
An equivalent is with 'WHERE EXISTS' :
SELECT m.*
FROM myTable m
WHERE EXISTS
(
SELECT *
FROM myTable m2
WHERE m2.include = 1
AND m2.nameid = m.nameid
)
You could see the difference here :
Can an INNER JOIN offer better performance than EXISTS
And why you have to use a Where exists when you have a filter with a lot of IDs :
Difference between EXISTS and IN in SQL?
I think this query identifies the nameid values you want included in your main query.
SELECT DISTINCT nameid
FROM YourTable
WHERE include = 1;
If that is true, incorporate it as a subquery and use an INNER JOIN with YourTable to return only those rows for which a nameid value is associated with include = 1 ... in any row of the table.
SELECT id, nameid, name, score, diff, include
FROM
YourTable AS y
INNER JOIN (
SELECT DISTINCT nameid
FROM YourTable
WHERE include = 1
) AS q
ON y.nameid = q.nameid;
The Access query designer will probably substitute square brackets plus a dot in place of the parentheses enclosing the subquery.
SELECT id, nameid, name, score, diff, include
FROM
YourTable AS y
INNER JOIN [
SELECT DISTINCT nameid
FROM YourTable
WHERE include = 1
]. AS q
ON y.nameid = q.nameid;
You need a subquery - as follows:
SELECT *
FROM tablename
WHERE nameid IN
(
SELECT DISTINCT nameid
FROM tablename
WHERE include = 1
)
SELECT * FROM yourTable WHERE nameid IN (SELECT DISTINCT nameid FROM yourTable WHERE include=1)
What you do is, select every row, whose nameid is in your subquery.
The subquery selects the nameid for rows where include=1.