SQL query, limit to 1 result per specif column - mysql

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

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

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.

groupby query by year

shipwynum is the primary key for convertship table.
Actually this query getting data correct, for year 2008 only. When i replace 2008 with any other year then also getting data correct for that year. This query display the total records for that year not in TotalCount. TotalCount has always one becoz i have group by with shipwynum.
But i want to get data for 1000 to 2011 separately(instead a particular year like 2008) in this one query and TotalCount should display the counts for every year.
I have this query :=
select
distinct
count(con.shipwynum) as TotalCount,
con.shipwynum,
s.deldat,
s.deldat as DeliveryQuarter,
left(s.deldat,4) as DelYear
from convertship con
left join shipscheduled s on con.shipwynum = s.shipwynum and s.deleted = 'N'
where left(s.deldat,4) > 1000 and left(s.deldat,4) <= 2008 and
left(con.condat,4) > 2008 and
con.deleted = 'N' and
con.wytypid in ('66', '10', '11', '12', '13', '14', '15', '16', '17','18') and
s.wytypid not in ('66', '10', '11', '12', '13', '14', '15', '16', '17','18')
group by con.shipwynum
Any help or ideas would be greatly appreciated.
Thanks a lot.
I think you're trying to count number of rows for each year?
From what i assume,
there is one main table convertship and you want to join convertship to shipscheduled.
Then do the group by on that data according to its left(con.condat,4) value.
select distinct
count(con.shipwynum) as TotalCount,
con.shipwynum,
s.deldat,
s.deldat as DeliveryQuarter,
left(s.deldat,4) as DelYear,
left(con.condat,4) as ConYear
from
convertship con
inner join
shipscheduled s on con.shipwynum = s.shipwynum
where
left(s.deldat,4) > 1000 and
left(s.deldat,4) <= 2008 and
-- left(con.condat,4) > 2008 and
con.deleted = 'N' and
s.deleted = 'N' and
con.wytypid in ('66','10','11','12','13','14','15','16','17','18') and
s.wytypid not in ('66','10','11','12','13','14','15','16','17','18')
group by
left(con.condat,4)
I assume the convertship table is not too big, if not this will not work.
Try:
select count(con.shipwynum) as TotalCount,
con.shipwynum,
s.deldat,
s.deldat as DeliveryQuarter,
left(s.deldat,4) as DelYear
from convertship con
left join shipscheduled s
on con.shipwynum = s.shipwynum and
s.deleted = 'N' and
left(s.deldat,4) > 1000 and
left(s.deldat,4) < left(con.condat,4) and
s.wytypid not in ('66', '10', '11', '12', '13', '14', '15', '16', '17','18')
where con.deleted = 'N' and
con.wytypid in ('66', '10', '11', '12', '13', '14', '15', '16', '17','18') and
group by con.shipwynum, left(s.deldat,4)
Note that since deldat and DeliveryQuarter are neither grouped by nor aggregated, their values in the output will essentially be random (within the DelYear).

mysql group_concat order by utf8

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.