Mysql - Order rows that have same columns content - mysql

have a Mysql table like that
id primary key ( idstudy, idarea and idcategory are foreign keys )
**** Table : Operations
id idstudy idarea idcategory content lang
1 22 11 3 content1EN EN
2 22 11 3 content1FR FR
3 22 11 3 Content2FR FR
4 22 11 3 Content2EN EN
5 35 10 5 Content5EN EN
6 35 10 5 Content5FR FR
7 35 23 12 Content5EN EN
8 35 23 12 Content5FR FR
My goal : to assemble language to same row ( FR and EN) to get one row with one column in plus ( ContentEN for example) and remove lang column.
but my problème my table is not in order, and i cant reconnize by id, all i know are idstudy idarea and idcategory but those both are not unique , and sometimes i have 3 rows that are same except (id and content)
I have solution but i dont know how to write it in mysql : is to find all records with ( same idstudy same idarea same idcategory ) in one language then order them by adding column with ( 1 for first result, 2 for the second ...)
**** Table : Operations after order of groups ( idstudy, idarea, idcategory) in each language with new column ( order)
id idstudy idarea idcategory content lang order
1 22 11 3 content1EN EN 1
2 22 11 3 content1FR FR 1
3 22 11 3 Content2FR FR 2
4 22 11 3 Content2EN EN 1
5 35 10 5 Content5EN EN 1
6 35 10 5 Content5FR FR 1
7 35 23 12 Content5EN EN 1
8 35 23 12 Content5FR FR 1
I just need this result , after to assemble iwill do it using nodejs
note: sorry if my explanation is not so good.

Try this:
SELECT id, idstudy, idarea, idcategory, content, lang, dense_rank as 'order'
FROM (
SELECT
#dense:=IF(#prev_col1=t.idstudy AND #prev_col2=t.idarea AND #prev_col3=t.idcategory AND #prev_col4=t.lang, IF(#prev_col5=t.content, #dense, #dense+1), 1) AS dense_rank,
t.*,
#prev_col1:=t.idstudy, #prev_col2:=t.idarea, #prev_col3:=t.idcategory, #prev_col4:=t.lang, #prev_col5:=t.content
FROM (SELECT * FROM t1 ORDER BY idstudy, idarea, idcategory, lang, content ) t,
(SELECT #dense:=1, #prev_col1:=NULL, #prev_col2:=NULL, #prev_col3:=NULL, #prev_col4:=NULL, #prev_col5:=NULL) var
) F
ORDER BY idstudy, idarea, idcategory, lang, content;
In MySql you can mimic ms-sql analytics functions in this way Analytical Function in MySQL - ROW_NUMBER, RANK, DENSE_RANK
In SQL-Sever you could use DENSE_RANK()
SELECT *, DENSE_RANK() OVER (PARTITION BY idstudy, idarea, idcategory, lang ORDER BY content) [order]
FROM tableName

Fianllay i found another solution , i made two tables with same structure ( french and english), regenerate id of eeach table ( to be 1.2.3.for each).
As i have 500 rows in each table i checked each row if its Ok ( each id must concern same content in two languages )
Special thanks to #MtwStark for his time :) i appreciate your help
Sometimes when we try to explain our problem we find the solution :)

Related

How to insert rows for each of the TYPE column?

How to insert rows for each of the type column? If there is two type, type 1 and type 2, then I need to insert two rows and also need to change the order and id value for whole table.
current status:
CHOICE Table
id choice type order
1 AA 1 1
2 BB 1 2
3 CC 1 3
4 AAA 2 4
5 BBB 2 5
6 CCC 2 6
7 DDD 2 7
Required updated table:
Now i wan to insert choice "000" for each type. The updated table will be look like bellow. How can I achieve this?
updated CHOICE Table
id choice type order
1 000 1 1
2 AA 1 2
3 BB 1 3
4 CC 1 4
5 000 2 5
6 AAA 2 6
7 BBB 2 7
8 CCC 2 8
9 DDD 2 9
here, id and order column serialized again.
The actual table is too big, so I cannot insert by edit. Please help for this complex query. I have no clue to solve this.
Use insert . . . select to insert the rows:
insert into choice (choice, type)
select distinct '000', type
from choice;
This assumes that id is automatically assigned (and it will be different from your example).
However, it looks like you want to update the order as well. For this, I would suggest an update:
update choice c join
(select c2.*,
row_number() over (partition by choice order by (order is null) desc, order) as new_order
from choice c2
) c2
on c.id = c2.id
set c.order = c2.new_order;
As an editorial comment, order is a very bad choice for a column name because it is a SQL keyword.

select rows in mysql with latest date for each quiz_id repeated multiple times

I have a table where each quiz ID is repeated multiple times. there is a date in front of each quiz id in each row. I want to select entire row for each quiz ID where date is latest with user. The date format is mm/dd/YYYY.
Sample -
USER_ID Quiz_id Name Date Marks .. .. ..
1 2 poly 4/3/2020 27
1 2 poly 4/3/2019 98
1 4 moro 4/3/2020 09
2 5 cat 4/12/2015 87
2 4 moro 4/3/2009 56
2 6 PP 4/3/2011 76
3 2 poly 4/3/2020 12
3 2 poly 5/3/2020 09
3 7 dog 4/3/2011 23
I want result look like this:Result
USER_ID Quiz_id Name Date Marks .. .. ..
1 2 poly 4/3/2020 27
1 4 moro 4/3/2020 09
2 5 cat 4/12/2015 87
2 4 moro 4/3/2009 56
2 6 PP 4/3/2011 76
3 2 poly 5/3/2020 09
3 7 dog 4/3/2011 23
You can use rank function to get the desired result:
Demo
SELECT A.* FROM (
SELECT A.*, RANK() OVER(PARTITION BY USER_ID,QUIZ_ID, NAME ORDER BY DATE DESC) RN FROM
Table1 A ORDER BY USER_ID) A WHERE RN = 1 ORDER BY USER_ID, QUIZ_ID;
I don't have MySQL installed so you will need to test and report back. The general idea is to identify the row of interest using max and a group by (table t). As the Date column appears to be text column (MySQL uses the format YYYY-MM-DD for dates) you will need to convert it to a date with str_to_date() so you can use the max() aggregate function. Finally, join with the original table (here table t2 to do the date conversion), as only the aggregate column(s) and columns named in the group by are well defined (in table t1), i.e.:
select USER_ID, Quiz_id, Date, Marks from (
select USER_ID, Quiz_id, max(str_to_date(Date, '%m/%d/%Y')) as Date2 from quiz group by 1, 2
) as t natural join (
select *, str_to_date(Date, '%m/%d/%Y') Date2 from Quiz
) as t2;
I don't recall off-hand but Date might be reserved word, in which case you will need to quote the column name, or ideally rename said column to use a better name.
Also, the original table is not in 3rd normal form as Quiz_id depends on Name. Quiz_id, as implied, should be a foreign key to a lookup table that holds the Name.

SQL - Max value from a group by when creating a new field

I have a database with a table called BOOKINGS containing the following values
main-id place-id start-date end-date
1 1 2018-8-1 2018-8-8
2 2 2018-6-6 2018-6-9
3 3 2018-5-5 2018-5-8
4 4 2018-4-4 2018-4-5
5 5 2018-3-3 2018-3-10
5 1 2018-1-1 2018-1-6
4 2 2018-2-1 2018-2-10
3 3 2018-3-1 2018-3-28
2 4 2018-4-1 2018-4-6
1 5 2018-5-1 2018-5-15
1 3 2018-6-1 2018-8-8
1 4 2018-7-1 2018-7-6
1 1 2018-8-1 2018-8-18
1 2 2018-9-1 2018-9-3
1 5 2018-10-1 2018-10-6
2 5 2018-11-1 2018-11-5
2 3 2018-12-1 2018-12-25
2 2 2018-2-2 2018-2-19
2 4 2018-4-4 2018-4-9
2 1 2018-5-5 2018-5-23
What I need to do is for each main-id I need to find the largest total number of days for every place-id. Basically, I need to determine where each main-id has spend the most time.
This information must then be put into a view, so unfortunately I can't use temporary tables.
The query that gets me the closest is
CREATE VIEW `MOSTTIME` (`main-id`,`place-id`,`total`) AS
SELECT `BOOKINGS`.`main-id`, `BOOKINGS`.`place-id`, SUM(DATEDIFF(`end-date`, `begin-date`)) AS `total`
FROM `BOOKINGS`
GROUP BY `BOOKINGS`.`main-id`,`RESERVATION`.`place-id`
Which yields:
main-id place-id total
1 1 24
1 2 18
1 5 5
2 1 2
2 2 20
2 4 9
3 1 68
3 2 24
3 3 30
4 1 5
4 2 10
4 4 1
5 1 19
5 2 4
5 5 7
What I need is then the max total for each distinct main-id:
main-id place-id total
1 1 24
2 2 20
3 1 68
4 2 10
5 1 19
I've dug through a large amount of similar posts that recommend things like self joins; however, due to the fact that I have to create the new field total using an aggregate function (SUM) and another function (DATEDIFF) rather than just querying an existing field, my attempts at implementing those solutions have been unsuccessful.
I am hoping that my query that got me close will only require a small modification to get the correct solution.
Having hyphen character - in column name (which is also minus operator) is a really bad idea. Do consider replacing it with underscore character _.
One possible way is to use Derived Tables. One Derived Table is used to determine the total on a group of main id and place id. Another Derived Table is used to get maximum value out of them based on main id. We can then join back to get only the row corresponding to the maximum value.
CREATE VIEW `MOSTTIME` (`main-id`,`place-id`,`total`) AS
SELECT b1.main_id, b1.place_id, b1.total
FROM
(
SELECT `main-id` AS main_id,
`place-id` AS place_id,
SUM(DATEDIFF(`end-date`, `begin-date`)) AS total
FROM BOOKINGS
GROUP BY main_id, place_id
) AS b1
JOIN
(
SELECT dt.main_id, MAX(dt.total) AS max_total
FROM
(
SELECT `main-id` AS main_id,
`place-id` AS place_id,
SUM(DATEDIFF(`end-date`, `begin-date`)) AS total
FROM BOOKINGS
GROUP BY main_id, place_id
) AS dt
GROUP BY dt.main_id
) AS b2
ON b1.main_id = b2.main_id AND
b1.total = b2.max_total
MySQL 8+ solution would be utilizing the Row_Number() functionality:
CREATE VIEW `MOSTTIME` (`main-id`,`place-id`,`total`) AS
SELECT b.main_id, b.place_id, b.total
FROM
(
SELECT dt.main_id,
dt.place_id,
dt.total
ROW_NUMBER() OVER (PARTITION BY dt.main_id
ORDER BY dt.total DESC) AS row_num
FROM
(
SELECT `main-id` AS main_id,
`place-id` AS place_id,
SUM(DATEDIFF(`end-date`, `begin-date`)) AS total
FROM BOOKINGS
GROUP BY main_id, place_id
) AS dt
GROUP BY dt.main_id
) AS b
WHERE b.row_num = 1

MySQL multiple count based on two column with multiple GROUP BY in single table

I have a query like below, it is working fine but not optimized, since it takes 1.5 sec to run. How to make this to an optimized result?
select h.keyword_id,
( select count(DISTINCT(user_id)) from history where category_id = 6
and h.keyword_id=keyword_id group by keyword_id ) as cat_6,
( select count(DISTINCT(user_id)) from history where category_id = 7
and h.keyword_id = keyword_id group by keyword_id ) as cat_7
from
history h group by h.keyword_id
History table
his_id keyword_id category_id user_id
1 1 6 12
2 1 6 12
3 1 7 12
4 1 7 12
5 2 6 13
6 2 6 13
7 2 7 13
8 3 6 13
Result:
keyword_id cat_6 cat_7
1 2 2 (unique users)
2 2 1
3 1 0
You can rewrite your query like this:
select h.keyword_id,
count(distinct if(category_id = 6, user_id, null)) as cat_6,
count(distinct if(category_id = 7, user_id, null)) as cat_7
from
history h
group by h.keyword_id
Your desired result based on the sample data is by the way false. In each keyword_id there's always just one distinct user_id.
you can see the query in action in an sqlfiddle here
For more optimization, you'd have to post the result of show create table history and the output of explain <your_query>;

What should be the MySQL query having dynamic group by cluase?

Need MySQL query for below problem
Consider a table having student and their marks in a particular subject
Schema
std_id int(11)
marks int(11)
Sample data
std_id marks
1 10
2 15
3 90
4 120
5 25
6 29
7 121
8 122
Now I have an web app in which a form will take a input (int) from user.
For eg 12
then I am required to show total number of student ids (std_id) and their corresponding marks group.
Eg
std_total (tot no of students) group (marks range we got from form)
1 0-11
1 12-23
2 24-35
1 84-95
3 120-131
#Barmar Your answer was almost correct, I made few changes to clean the output. Your query gives output as below :
0-11 2
1-12 2
2-13 1
3-14 1
4-15 1
6-17 1
7-18 2
My query return Outout as
0-11 2
12-23 2
24-35 1
36-47 1
48-59 1
72-83 1
84-95 2
SELECT CONCAT(FLOOR(marks/12)*12, '-', FLOOR(marks/12)+11*(FLOOR(marks/12))+11) AS `group`, COUNT(*) as `std_total`
FROM yourTable
GROUP BY `group`
Use division and FLOOR() to get the beginning of each range.
SELECT CONCAT(FLOOR(marks/12), '-', FLOOR(marks/12)+11) AS `group`, COUNT(*) as `std_total`
FROM yourTable
GROUP BY `group`