mysql group_concat order by utf8 - mysql

I have the following problem
I have 3 table (all of the are used utf8 / utf8_general_ci encoding)
movies, channels, i also have 3 table movie_channels which
is just a combination of the other two with just 2 fields: movie_id,channel_id
here is my channels table (code,name)
'1', 'ОРТ'
'2', 'ТК Спорт'
'3', 'ТК ТНВ'
'4', 'НТВ'
'5', 'НТВ+'
'6', 'TSN'
here is my movie_channels table (movie _id, channel_id) channel_id references code field in channels table
'19', '2'
'19', '6'
'95', '1'
'95', '4'
'96', '1'
'96', '4'
'97', '1'
'97', '4'
'98', '1'
'98', '4'
'99', '1'
'99', '4'
'100', '1'
'100', '4'
don't mind quotes on id values. they are all ints of course, not chars, it's just pasting issue
for each movie i need to display comma separated list of channels
i used mysql group_concat
select t.movie_id,( select group_concat(c.name) from
movie_channels mc
join channels c on mc.channel_id=c.code
where mc.movie_id = t.movie_id
order by code desc )as audio_channel from movies t
but I dont like the order of concat for movie_id #19 i need the above sql to display TSN,ТК Спорт but it keeps returning me ТК Спорт,TSN . I tried to use order by code desc with no luck ,tried order by char_length(asc) with no success
any ideas ?

If for every movie you want to list all the channels that are showing that movie, you need something like this:
SELECT
mc.movie_id,
GROUP_CONCAT(c.name) AS channels
FROM movie_channels AS mc
JOIN channels AS c
ON c.code = mc.channel_id
GROUP BY mc.movie_id
ORDER BY c.code DESC;

You can add a ORDER BY clause inside the GROUP_CONCAT() aggregate to adjust the ordering of the grouped string.

Related

How to check values in mysql for preceeding rows and using them to find sum

I have to find the time, that the system that is based on this table has elapsed while having code '100', so firstly i thought that I have to find the newest row of the xID group and after that, check the previous rows if their code is 100, if so i have to proceed with previous previous row till it gets a 200 value, after that it finds the time from the following row of 200 hundred till now (value 100).
ID xID createdDate CODE
1 '1', '2019-07-27 11:52:01', '100'
2 '1', '2019-07-27 11:54:01', '200'
3 '2', '2019-09-03 05:10:02', '200'
4 '2', '2019-09-03 05:12:02', '200'
5 '3', '2019-09-02 05:12:02', '200'
6 '3', '2019-09-02 05:12:02', '100'
7 '3', '2019-09-02 05:12:02', '200'
8 '4', '2019-09-02 05:13:02', '200'
9 '5', '2019-09-03 05:10:03', '200'
10 '6', '2018-12-13 05:03:02', '200'
So this query must for each group of xID find the total time for which the system has been with code 100 until now. Hope I've been clear. And here is the sql so far.
select id, createdDate, code
from wlogs
where id in (
select max(id)
from wlogs
group by xid
)
order by xid;
EDIT:
MYSQL VERSION 8.0
RESULT must be something like this where the column totTimeWithCode100 must show the time in seconds or minutes doesn't matter, for each type of xID.
xID totTimeWithCode100
'1', '500'
'2', '2'
'3', '33'
'4', '200'
'5', '40'
'6', '200'
These rows
Prior to MySQL 8.0, we can use of user-defined variables (in a way that is unsupported) in carefully crafted SQL that takes advantage of behavior that is repeatably observed but not guaranteed. (The MySQL Reference Manual warns specifically about this usage of user-defined variables.)
Something like this:
SELECT s.xid AS `xID`
, IFNULL(SUM(s.secs_in_code100),0) AS `totTimeWithCode100`
FROM (
SELECT IF(#prev_xid = t.xid AND #prev_code = 100, TIMESTAMPDIFF(SECOND,#prev_date,t.createddate),0) AS secs_in_code100
, #prev_xid := t.xid AS xid
, #prev_date := t.createddate AS createddate
, #prev_code := t.code AS code
FROM ( SELECT #prev_xid := ''
, #prev_date := '1970-01-02 03:00'
, #prev_code := ''
) i
CROSS
JOIN wlogs t
ORDER
BY t.xid
, t.createddate
) s
GROUP BY s.xid
ORDER BY s.xid
With MySQL 8.0, we can avoid the user-defined variables by using analytic/window functions.
You can get the result you want by finding all the rows with CODE = 100 for a given xID that are immediately followed (in time) by a row with CODE != 100. This can be done by LEFT JOINing the rows with CODE != 100 to the preceding row if that row has CODE = 100:
SELECT w.xID, COALESCE(SUM(TIMESTAMPDIFF(SECOND, w1.createdDate, w2.createdDate)), 0) AS totTimeWithCode100
FROM (SELECT DISTINCT xID FROM wlogs) w
LEFT JOIN (SELECT *
FROM wlogs
WHERE CODE = 100) w1 ON w1.xID = w.xID
LEFT JOIN wlogs w2 ON w2.xID = w1.xID
AND w2.createdDate = (SELECT MIN(createdDate)
FROM wlogs w3
WHERE w3.xID = w1.xID AND
w3.createdDate > w1.createdDate)
GROUP BY w.xID
ORDER BY w.xID;
Demo on dbfiddle

How to get last record of each day in mysql?

I want to get last record of each day in mysql.Location<id, date, place_id> table has multiple entries on each day. This Location table has place_id and time at which place_id is inserted.
Also taking consider if place_id is not present then return second last record which has place_id. In following table for NULL, '2016-04-06 18:52:06' record we are returning '13664', '2016-04-06 12:57:30', which is second last record on '2016-04-06' (6th March) and has place_id.
One more thing, on single day, there would be more place_id, see the following table..
id || place_id || date
'1', '47', '2016-04-05 18:09:37'
'2', '48', '2016-04-05 12:09:37'
'3', '13664', '2016-04-06 12:57:30'
'4', '9553', '2016-04-08 10:09:37'
'5', NULL, '2016-04-06 18:52:06'
'6', '9537', '2016-04-07 03:34:24'
'7', '9537', '2016-04-07 03:34:24'
'8', '656', '2016-04-07 05:34:24'
'9', '7', '2016-04-07 05:34:57'
When I run following query it returns following result
Query I run the following query but it is giving me wrong result
`Location<id, place_id, date>`
select L1.place_id, L1.date from
Location1 L1
Left join
Location1 L2
on
Date(L1.date) = Date(L2.date)
And
L1.date < L2.date
where
L2.date is null
group by L1.date;
Result I want:
id....place_id ........date
'1', '47', '2016-04-05 18:09:37'
'3', '13664', '2016-04-06 12:57:30'
'4', '9553', '2016-04-08 10:09:37'
'9', '7', '2016-04-07 05:34:57'
You may give it a try:
SELECT
L.id,
L.place_id,
L.date
FROM Location L
INNER JOIN
(
SELECT
MAX(date) max_time
FROM Location
GROUP BY Date(`date`)
) AS t
ON L.date = t.max_time
SQL FIDDLE DEMO
SQL FIDDLE DEMO2
[Based on your expected output]
Can you try with the following query:
SELECT * FROM `Location` GROUP BY DATE(`date`) ORDER BY `date` DESC
What this query does is group the rows by descending date and show a row for each date.
Get the last record:
SELECT * FROM `Location` ORDER BY `date` LIMIT 1;
Get the last record that doesn't have a null as a value:
SELECT * FROM `Location` WHERE place_id IS NOT NULL ORDER BY `date` LIMIT 1;
Get records for all the places which are not null:
SELECT * FROM `Location` WHERE place_id IS NOT NULL GROUP BY `place_id` ORDER BY `date` DESC
Would this work?
select place_id, max(date) as MaxDate
from foo
where place_id is not NULL
group by place_id

SQL query, limit to 1 result per specif column

Given the query below, I can get a result set containing all new stories from the location id's listed in the query and sorted by date. What I don't understand is how to rewrite the query so that it is limited to 1 result (the latest) from each location ID.
Is it possible to do this, or should I just process the result set afterwards?
Thanks in advance,
SELECT node.title AS node_title, node.nid AS nid, node.created AS node_created
FROM
{node} node
INNER JOIN {field_data_field_story_location} field_data_field_story_location
ON node.nid = field_data_field_story_location.entity_id
AND (field_data_field_story_location.entity_type = 'node'
WHERE (( (node.status = '1') AND (node.type IN ('_news_story'))
AND (field_data_field_story_location.field_story_location_tid IN
('38', '44', '46', '45', '30', '36', '37', '29', '33', '34', '28', '56', '21', '49', '32')) ))
ORDER BY node_created DESC
You could process the result set afterwards, but it's not efficient in case of big amount of data.
To be more efficient you could write n queries (one for each field_story_location_tid) with limit 1 and then join the result set using the UNION sintax

MYSQL issue howto count result in master table not including all rows from a Detail table "labels" used in a join

To simplify the question I am only using a few field in my test table example
Master db
Id Description type cost
'1', 'Test1', '2', '100'
'2', 'Test2', '2', '100'
'3', 'Test3', '3', '100'
'4', 'Test4', '4', '100'
Labels db
ID Name Masterid
'1', 'Label1', '1'
'2', 'Label1', '2'
'3', 'Label2', '1'
'4', 'Label3', '1'
I would like to count all ID's and make summary for the cost field for all records in master containing label1 and label2 from labels
My Query
Select count(Distinct m.id) as andtall , sum(m.cost) as cost
from
master m
join labels l ON l.Masterid=m.id and l.name in ('Label1','Label2')
Since I am using Distinct in count that result will be correct, but Cost is wrong it's containg 3 records not 2.
'2', '300' I would like it to return 200 since only 2 records from master table should be returned.
Try this
SELECT
count( m.id ) as andtall,
sum( m.cost ) as cost
FROM
master m
JOIN (
SELECT
Masterid
FROM
labels l
WHERE
l.name in ('Label1', 'Label2')
GROUP BY master_id ) l ON l.Masterid = m.id

Mysql sort results without exclude others results

I have a list of localized results by country. I would first like to get the result of the Effective Country X first and then the others in the same. Is that possible?
If I set a where "anno_country" = 1 ... it excludes the results of other countries. I would like something like "order by country = 3" ...
Currently, this is my MySQL query :
SELECT DISTINCT *
FROM (`annonce`)
JOIN possede USING (`anno_id`)
JOIN annonceur USING (`ann_id`)
JOIN lang_pays USING (`pays_id`)
JOIN cat_lang USING (`cat_id`)
WHERE
`cat_id` IN ('4', '9', '5', '426', '6', '435', '7', '3', '8', '2')
AND
`anno_active` = 1
AND
`anno_mode` = 1
AND
`cat_lang`.`lang_id` = '3'
AND
`lang_pays`.`lang_id` = '3'
ORDER BY `anno_id` desc
Do you have an idea ?
You can use this:
ORDER BY (country != 3), anno_id DESC
this will show rows with country = 3 at the top, ordered by anno_id desc, and then all rows with country!=3 at the bottom, ordered by anno_id desc.
SELECT * FROMyourtableORDER BY (country= 'X') DESC,country
This will order by country x first then other countries.