Creating a log having the date of purchase - mysql

I need to create a log having the purchase date of an item.
Items can be owned by only one buyer at time. So, for example, if item1 was purchased by buyer2 in 2009 and after by buyer1 in 2015, then between 2009 and 2015 was owned by buyer2.
Here is my table:
+--------+------------+-----------+----------+
| id_doc | date | id_item | id_buyer |
+--------+------------+-----------+----------+
| 11 | 2016-06-07 | 1 | 4 |
| 10 | 2016-06-06 | 1 | 4 |
| 1 | 2015-11-30 | 1 | 1 |
| 9 | 2009-01-01 | 1 | 2 |
| 4 | 2001-01-12 | 1 | 2 |
| 8 | 1996-06-06 | 1 | 2 |
| 3 | 1995-05-29 | 1 | 1 |
| 2 | 1998-05-23 | 2 | 2 |
| 7 | 2014-10-10 | 3 | 2 |
| 6 | 2003-12-12 | 3 | 3 |
| 5 | 1991-01-12 | 3 | 2 |
+--------+------------+-----------+----------+
Here is a kind of table/view I need:
+------------+------------+-----------+----------+--------+
| date_from | date_to | id_item | id_buyer | id_doc |
+------------+------------+-----------+----------+--------+
| 2016-06-07 | - | 1 | 4 | 11 |
| 2016-06-06 | 2016-06-07 | 1 | 4 | 10 |
| 2015-11-30 | 2016-06-06 | 1 | 1 | 1 |
| 2009-01-01 | 2015-11-30 | 1 | 2 | 9 |
| 2001-01-12 | 2009-01-01 | 1 | 2 | 4 |
| 1996-06-06 | 2001-01-12 | 1 | 2 | 8 |
| 1995-05-29 | 1996-06-06 | 1 | 1 | 3 |
| 1998-05-23 | - | 2 | 2 | 2 |
| 2014-10-10 | - | 3 | 2 | 7 |
| 2003-12-12 | 2014-10-10 | 3 | 3 | 6 |
| 1991-01-12 | 2003-12-12 | 3 | 2 | 5 |
+------------+------------+-----------+----------+--------+
I've tried a lot with GROUP BY, GROUP_CONCAT, trying to access next record date, etc ... but I can't found out how to solve the problem.
Thanks in advance.

I finally found out the solution only for past purchases.
SELECT
main.id_doc, main.id_item, main.date AS "date_from", bi.date AS "date_to", main.id_buyer
FROM
MyTable main, MyTable bi
WHERE
bi.id_doc =
(
SELECT sub.id_doc
FROM MyTable sub
WHERE sub.id_item = main.id_item AND sub.date > main.date ORDER BY sub.date ASC LIMIT 1
);

Related

SQL : For each ID, only display the highest value from another column (can't group by)

I have this table here :
+---------+----------+------------+------------+
| idStep | idProj | dateStart | dateEnd |
+---------+----------+------------+------------+
| 1 | 1 | 2011-07-01 | 2011-09-01 |
| 1 | 2 | 2012-05-01 | 2012-05-10 |
| 1 | 3 | 2011-11-01 | 2012-01-20 |
| 2 | 1 | 2011-09-02 | 2011-11-30 |
| 2 | 2 | 2012-05-11 | 2012-06-01 |
| 2 | 3 | 2012-01-21 | 2012-04-01 |
| 3 | 1 | 2011-12-01 | 2012-07-07 |
| 3 | 2 | 2012-06-02 | 2012-07-01 |
| 3 | 3 | 2012-04-02 | NULL |
| 4 | 1 | 2012-07-08 | NULL |
| 4 | 2 | 2012-07-01 | 2012-07-21 |
| 5 | 2 | 2012-07-22 | 2012-07-23 |
+---------+----------+------------+------------+
I need to find the current step of each project by searching for the highest idStep of each idProject without using Group By, which is where I'm completely stuck. Without GROUP BY I just cannot get there.
Basically, the output should be this :
+---------+----------+------------+------------+
| idStep | idProj | dateStart | dateEnd |
+---------+----------+------------+------------+
| 3 | 3 | 2012-04-02 | NULL |
| 4 | 1 | 2012-07-08 | NULL |
| 5 | 2 | 2012-07-22 | 2012-07-23 |
+---------+----------+------------+------------+
I want to use a Query built like this
SELECT idProj,idStep
FROM table
WHERE idStep = (SELECT max(idStep) FOR EACH idProj)
I know that FOR EACH isn't SQL, I'm only trying to make my desired query structure readable.
You want a correlated subuqery:
SELECT idProj, idStep
FROM table t
WHERE t.idStep = (SELECT max(idStep)
FROM table t2
WHERE t2.idProj = t.idProj
);

Is there a mySQL procedure that can merge duplicate rows of data into one, then allow me to manipulate that data as if it were one row?

I'm trying to come up with a stored procedure that takes multiple rows that are exactly identical, and combines them into one row while summing one column, which can then be run through more stored procedures based on the sum of that one column.
I've tried a GROUP BY statement, but that doesn't actually group the rows together, because if I run the table through another procedure it performs actions as if each row were not combined. Performing a SELECT * FROM mytable query shows that each row was not actually combined into one.
Is there any way to permanently combine multiple rows into one singular row?
To start, I've got a table like this:
+-------+-----+--------+---------+------+-----+-----------+
| RowID | pID | Name | Date | Code | QTY | Purchased |
+-------+-----+--------+---------+------+-----+-----------+
| 1 | 1 | bob | 9/29/20 | 123 | 1 | |
| 2 | 1 | bob | 8/10/20 | 456 | 1 | |
| 3 | 2 | rob | 9/15/20 | 123 | 1 | |
| 4 | 2 | rob | 9/15/20 | 123 | 1 | |
| 5 | 2 | rob | 9/15/20 | 123 | 1 | |
| 6 | 2 | rob | 9/15/20 | 123 | 1 | |
| 7 | 2 | rob | 9/15/20 | 123 | 1 | |
| 8 | 3 | john | 7/12/20 | 987 | 1 | |
| 9 | 3 | john | 7/12/20 | 987 | 1 | |
| 10 | 4 | george | 9/12/20 | 684 | 1 | |
| 11 | 5 | paul | 2/2/20 | 454 | 1 | |
| 12 | 6 | amy | 1/12/20 | 252 | 1 | |
| 13 | 7 | susan | 5/30/20 | 131 | 1 | |
| 14 | 7 | susan | 6/6/20 | 252 | 1 | |
| 15 | 7 | susan | 5/30/20 | 131 | 1 | |
+-------+-----+--------+---------+------+-----+-----------+
By the end, i'd like to have a table like this:
+-------+-----+--------+---------+------+-----+-----------+
| RowID | pID | Name | Date | Code | QTY | Purchased |
+-------+-----+--------+---------+------+-----+-----------+
| 1 | 1 | bob | 9/29/20 | 123 | 1 | |
| 2 | 1 | bob | 8/10/20 | 456 | 1 | |
| 3 | 2 | rob | 9/15/20 | 123 | 5 | |
| 4 | 3 | john | 7/12/20 | 987 | 2 | |
| 5 | 4 | george | 9/12/20 | 684 | 1 | |
| 6 | 5 | paul | 2/2/20 | 454 | 1 | |
| 7 | 6 | amy | 1/12/20 | 252 | 1 | |
| 8 | 7 | susan | 5/30/20 | 131 | 2 | |
| 9 | 7 | susan | 6/6/20 | 252 | 1 | |
+-------+-----+--------+---------+------+-----+-----------+
Where exactly identical rows are combined into one row, and the QTY field is summed, that I can then add purchases to, or make deductions from the quantity as a total. Using GROUP BY statements can achieve this, but when I go to alter the quantity or add purchases to each person, it treats it like the first table, as if nothing was actually grouped.
So you have this table:
| RowID | pID | Name | Date | Code | QTY | Purchased |
+-------+-----+--------+---------+------+-----+-----------+
| 1 | 1 | bob | 9/29/20 | 123 | 1 | |
| 2 | 1 | bob | 8/10/20 | 456 | 1 | |
| 3 | 2 | rob | 9/15/20 | 123 | 1 | |
| 4 | 2 | rob | 9/15/20 | 123 | 1 | |
| 5 | 2 | rob | 9/15/20 | 123 | 1 | |
| 6 | 2 | rob | 9/15/20 | 123 | 1 | |
| 7 | 2 | rob | 9/15/20 | 123 | 1 | |
| 8 | 3 | john | 7/12/20 | 987 | 1 | |
| 9 | 3 | john | 7/12/20 | 987 | 1 | |
| 10 | 4 | george | 9/12/20 | 684 | 1 | |
| 11 | 5 | paul | 2/2/20 | 454 | 1 | |
| 12 | 6 | amy | 1/12/20 | 252 | 1 | |
| 13 | 7 | susan | 5/30/20 | 131 | 1 | |
| 14 | 7 | susan | 6/6/20 | 252 | 1 | |
| 15 | 7 | susan | 5/30/20 | 131 | 1 | |
The best way, as has been suggested, is to create a new table with the content of your query, then to rename the old table, and the new table to the original table's name, to check if everything is all right, and to drop the original table if yes.
CREATE TABLE indata_new AS
WITH grp AS (
SELECT
MIN(rowid) AS orowid
, pid
, name
, MAX(date) AS date
, code
, SUM(qty) AS qty
FROM indata
GROUP BY
pid
, name
, code
)
SELECT
ROW_NUMBER() OVER(ORDER BY orowid ASC) AS rowid
, *
FROM grp;
ALTER TABLE indata RENAME TO indata_old;
ALTER TABLE indata_new RENAME TO indata;
-- if "indata" now contains the data you want ...
SELECT * FROM indata;
-- out rowid | orowid | pid | name | date | code | qty
-- out -------+--------+-----+--------+------------+------+-----
-- out 1 | 1 | 1 | bob | 2020-09-29 | 123 | 1
-- out 2 | 2 | 1 | bob | 2020-08-10 | 456 | 1
-- out 3 | 3 | 2 | rob | 2020-09-15 | 123 | 5
-- out 4 | 8 | 3 | john | 2020-07-12 | 987 | 2
-- out 5 | 10 | 4 | george | 2020-09-12 | 684 | 1
-- out 6 | 11 | 5 | paul | 2020-02-02 | 454 | 1
-- out 7 | 12 | 6 | amy | 2020-01-12 | 252 | 1
-- out 8 | 13 | 7 | susan | 2020-05-30 | 131 | 2
-- out 9 | 14 | 7 | susan | 2020-06-06 | 252 | 1
-- you can ...
DROP TABLE indata_old;

Mysql Row To Column Select Specific Data

I have column user and rating.
SELECT rating.idUser, user.nmUser, rating.idBengkel, rating.nilai FROM `rating`
JOIN user on rating.idUser = user.idUser
WHERE rating.idBengkel=1 or rating.idBengkel=2
Result :
+--------+---------------------------+-----------+-------+
| idUser | nmUser | idBengkel | nilai |
+--------+---------------------------+-----------+-------+
| 10 | Hudson mas77 | 1 | 5 |
| 11 | Vina Nurfadzilah | 1 | 5 |
| 12 | Angelica Amartya | 1 | 5 |
| 15 | Syahrul K | 1 | 4 |
| 27 | Ashar Murdihastomo | 1 | 5 |
| 28 | Eril Obeit Choiri | 1 | 2 |
| 29 | Ariyadi | 1 | 3 |
| 30 | Robertus Dwian Augusta | 1 | 4 |
| 31 | Irfan Setiaji | 1 | 4 |
| 33 | Baby Ayuna | 1 | 5 |
| 9 | Nur k hamid | 2 | 5 |
| 10 | Hudson mas77 | 2 | 5 |
| 13 | Yuana Putra | 2 | 4 |
| 14 | Nanda Aulia Irza Ramadhan | 2 | 4 |
| 26 | taufiq rahman | 2 | 5 |
| 27 | Ashar Murdihastomo | 2 | 5 |
| 28 | Eril Obeit Choiri | 2 | 5 |
| 30 | Robertus Dwian Augusta | 2 | 4 |
| 44 | halim budiono | 2 | 1 |
+--------+---------------------------+-----------+-------+
When i try to get similar records using this query
SELECT rating.idUser, user.nmUser FROM rating
JOIN user
ON rating.idUser = user.idUser
WHERE rating.idBengkel = 1 and rating.idUser
IN (SELECT rating.idUser from rating WHERE rating.idBengkel = 2)
ORDER by idUser
Result :
+-----------+------------------------+
| idUser | nmUser |
+-----------+------------------------+
| 10 | Hudson mas77 |
| 27 | Ashar Murdihastomo |
| 28 | Eril Obeit Choiri |
| 30 | Robertus Dwian Augusta |
+-----------+------------------------+
The result work fine, but I want show column 'nilai' as ItemX and ItemY. Those are user similar data. In this case I have 4 similar user who rate on idBengkel=1 and idBengkel=2 as the results above. I want it like the table below.
+--------+------------------------+-------+-------+
| idUser | nmUser | ItemX | ItemY |
+--------+------------------------+-------+-------+
| 10 | Hudson mas77 | 5 | 5 |
| 27 | Ashar Murdihastomo | 5 | 5 |
| 28 | Eril Obeit Choiri | 2 | 5 |
| 30 | Robertus Dwian Augusta | 4 | 4 |
+--------+------------------------+-------+-------+
I need solution for this and i was trying with this solution in https://stackoverflow.com/a/7976379/12396302 but it resulting more than one row. Please help me, I cant implement that query's solution. Regards!
I think you need below query -
SELECT rating.idUser,
user.nmUser,
MAX(CASE WHEN rating.idBengkel = 1 THEN rating.nilai END) ItemX,
MAX(CASE WHEN rating.idBengkel = 2 THEN rating.nilai END) ItemY,
FROM `rating`
JOIN user on rating.idUser = user.idUser
WHERE rating.idBengkel IN (1, 2)
GROUP BY rating.idUser,
user.nmUser

Complex pivoting in mysql

I have a table in MySQL that has data and I want to achieve some sort of pivoting from the table, which has become complicated for me. I have tried looking into this but nothing seems to work for me. This is the structure of my table :
roomid| day| 1 | 2 | 3 | 4 | 5 | 6 |
------+----+---+---+---+---+---+---+
1 | 1 |BIO| | | | | |
1 | 2 | |CHE| | | | |
1 | 3 | | | | | |ENG|
1 | 4 | | |KIS| | | |
1 | 5 | | | | | |PHY|
2 | 1 |BIO| | | | | |
2 | 2 | |CHE| | | | |
2 | 3 | | | | |ENG| |
2 | 4 | | |KIS| | | |
2 | 5 | | | | | |PHY|
This table is holding timetable data, the roomid is id for rooms and the day is days from monday to friday (1 to 5). The columns 1 to 6 are period ids.
I need to organize the data to achieve results that show period ids for each class, each day. something like this :
|roomid| 1 | 2 | 3 | 4 | 5 | 6 | 1 | 2 | 3 | 4 | 5 | 6 | 1 | 2 | 3 | 4 | 5 | 6 | 1 | 2 | 3 | 4 | 5 | 6 | 1 | 2 | 3 | 4 | 5 | 6 |
-------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1 |BIO| | | | | | |CHE| | | | | | | | | |ENG| | |KIS| | | | | | | | |PHY|
2 |BIO| | | | | | |CHE| | | | | | | | | |ENG| | |KIS| | | | | | | | |PHY|
Kindly notice that the period ids repeat themselves for different days.
You can use conditional aggreagtion:
select room_id,
max(case when day = 1 then slot_1 end) as day_1_slot_1,
max(case when day = 1 then slot_2 end) as day_1_slot_2,
. . .
max(case when day = 2 then slot_1 end) as day_2_slot_1,
max(case when day = 2 then slot_2 end) as day_2_slot_2,
. . .
from schedule s
group by room_id
While not claiming to be a definitive solution, a normalised design might be somewhat as follows. Frankly, it stretches credulity to suggest that the present design is somehow more appropriate than this.
+--------+-----+------+---------+
| roomid | day | slot | subject |
+--------+-----+------+---------+
| 1 | 1 | 1 | BIO |
| 2 | 1 | 2 | BIO |
| 1 | 2 | 2 | CHE |
| 2 | 2 | 2 | CHE |
| 1 | 4 | 3 | KIS |
| 2 | 4 | 3 | KIS |
| 2 | 3 | 5 | ENG |
| 1 | 3 | 6 | ENG |
| 1 | 5 | 6 | PHY |
| 2 | 5 | 6 | PHY |
+--------+-----+------+---------+

Grouping, yet concatenating values from within the group in MySQL

I have a simple MySQL table as such:
| CUST_ID | VISIT | PROD_ID |
|---------|-------|---------|
| 1 | 1 | 3473 |
| 1 | 2 | 324 |
| 1 | 2 | 324 |
| 2 | 1 | 426 |
| 2 | 2 | 4418 |
| 3 | 1 | 4523 |
| 4 | 1 | 976 |
| 4 | 1 | 86 |
| 4 | 2 | 3140 |
| 4 | 3 | 1013 |
And I would like to transform it to this:
| CUST_ID | VISIT | PROD_IDs |
|---------|-------|----------|
| 1 | 1 | 3473 |
| 1 | 2 | 324, 324 |
| 2 | 1 | 426 |
| 2 | 2 | 4418 |
| 3 | 1 | 4523 |
| 4 | 1 | 976, 86 |
| 4 | 2 | 3140 |
| 4 | 3 | 1013 |
This is kinda an ugly hack, I get it.
I have no idea how to cleanly create such a thing. I've tried a variety of unsuccessful grouping strategies. Even a clue or hint in the right direction would be great. Thanks.
If you're trying to group by cust_id + visit, then you can do that and use a GROUP CONCAT on the PROD_ID field, for example:
SELECT
CUST_ID,
VISIT,
GROUP_CONCAT(PROD_ID) PROD_IDS
FROM
table
GROUP BY
CUST_ID,
VISIT
Reference: GROUP CONCAT