MySQL limit results per category - sql

Each item in c_data is in a category/section. I would like to limit how many items are displayed per category, rather than limiting the total number of items retrieved. Obviously if I add something like "limit 20" to the query, it will only fetch 20 results in total, rather than 20 results per category.
SELECT cm.id,
cm.title AS cmtitle,
cm.sectionid,
cm.type AS cmtype,
cd.id,
cd.time,
cd.link,
cd.title,
cd.description,
cd.sectionid AS sectionid
FROM c_main AS cm
JOIN c_data AS cd ON cd.sectionid=cm.sectionid
WHERE cd.sectionid=cm.sectionid
ORDER by id ASC
The field with the category is "sectionid".

MySQL doesn't have any ranking functionality, but you can use a variable to create a psuedo row number.
Use:
SELECT x.*
FROM (SELECT cm.id,
cm.title AS cmtitle,
cm.sectionid,
cm.type AS cmtype,
cd.id AS cd_id,
cd.time,
cd.link,
cd.title,
cd.description,
cd.sectionid AS cd_sectionid,
CASE
WHEN #sectionid != cm.sectionid THEN #rownum := 1
ELSE #rownum := #rownum + 1
END AS rank,
#sectionid := cm.sectionid
FROM C_MAIN cm,
C_DATA cd,
(SELECT #rownum := 0, #sectionid := NULL) r
WHERE cm.sectionid = cd.sectionid
ORDER BY cm.sectionid) x
WHERE x.rank <= 20
ORDER BY id

The answers to this previous post should help you to solve that problem.
EDIT:
It should work with using row numbers.
I have not tried it, but this should work:
set #section = '';
set #num = 1;
SELECT y.*
FROM
(
SELECT
x.*,
#num := if(#section = sectionid, #num + 1, 1) as row_number,
#section := sectionid
FROM
(
SELECT
cm.id AS cm_id,
cm.title AS cmtitle,
cm.sectionid,
cm.type AS cmtype,
cd.id AS cd_id,
cd.time,
cd.link,
cd.title,
cd.description
FROM c_main AS cm
JOIN c_data AS cd ON ( cd.sectionid=cm.sectionid )
ORDER by cd.sectionid ASC, cm.id ASC
) x
) y
WHERE y.row_number <= 20;

Related

How to substitute “with” statement in mariadb 10.1

I use a third party software with MariaDB 10.1 How can I subsitute sql "with" statement (not available with MariaDB 10.1) ?
I would like to do something like that :
WITH mCte
AS (
SELECT
#row_num: = #row_num + 1 AS Cpt
,field1
FROM (
SELECT #row_num: = 0 AS row_num
,myField AS field1
FROM myTable
) AS T
)
SELECT *
FROM mCte
WHERE Cpt BETWEEN 1 AND 5
Thanks
I would suggest:
select #row_num := #row_num + 1 AS Cpt, field1
from myTable t cross join
(select #row_num := 0 as row_num) params
limit 5;
Normally, I would expect an order by in the query, but your code doesn't have one.

SQL sum based on the result

pre qty cur
--------------------
100 -1 99
99 -10 89
89 10 99
Hi, I would like to update the column pre, qty, cur. I tried to sum pre and qty then result cur will bring to the next pre column for continue the calculation.
So far this is my query.
SELECT `id`, `pre` , `qty`, `cur`, `pre`+`qty` AS `cur` FROM `inventory_logs`
If that is your desired output at the top of your question, you can use LAG to update your table in one shot instead of processing one cur at a time:
UPDATE inventory_logs
SET cur = pr.P
FROM inventory_logs JOIN (SELECT pre, qty, LAG(pre + qty, 0)
OVER (Partition by pre ORDER BY id asc) AS P
FROM inventory_logs) as pr
ON inventory_logs.pre = pr.pre;
From what I understand you have posted the expected results in your question.
You can use a recursive CTE:
WITH CTE AS(
SELECT ID,PRE,QTY,PRE+QTY AS CUR FROM inventory_logs WHERE ID=1
UNION ALL
SELECT T.ID, C.CUR AS PRE, T.QTY, C.CUR + T.QTY AS CUR
FROM CTE C
INNER JOIN inventory_logs T
ON T.ID = C.ID+1
)
SELECT * FROM CTE
Assuming ofcourse you want to start the calculation from ID =1 and are ordering by ID
Try it in sql,
UPDATE inventory_logs SET cur=pre + qty
SELECT id, pre , qty, cur FROM inventory_logs

Update Oracle table based on nested select incl. package function

I have a query which calls a function in a package to create a percentage value as a sum of about 30 columns.
What I'd like to do is update each row based on the "sum of counted columns" as a percentage.
The select query is:
SELECT
checklist_id,
row_status,
eba_cm_checklist_std.get_row_percent_complete(pc.id,pc.checklist_id,pc.max_col_num) AS percent_complete
FROM
(
SELECT
(
SELECT
COUNT(id)
FROM
eba_cm_checklist_columns
WHERE
checklist_id = r.checklist_id
) AS max_col_num,
r.*
FROM
eba_cm_checklist_rows r
ORDER BY
r.row_order,
r.name
) pc
and the package.function that creates the percentage is "eba_cm_checklist_std.get_row_percent_complete".
The query outputs the following:
checklist_id row_status percent_complete
97176759931088640236098007249022291412 Red 0
97176759931071715274623402440576404948 Red 0
97176759931071715274623402440576404948 Red 0
97176759931071715274623402440576404948 Red 0
97176759931088640236098007249022291412 Red 0
97176759931088640236098007249022291412 Red 0
97176759931081386681180319473974054356 Grey 100
97176759931051163535689953744606399956 Grey 100
The difficulty I'm having is that the expression is using a nested select statement based on the output of a function and I can't get my head around how to update the physical "eba_cm_checklist_rows" table based on the output of the query.
Basically, I want to do the following:
update set row_status = 'Green' where percent_complete = 100
Another option is to use bulk select/update:
declare
type t_rid_arr is table of rowid index by pls_integer;
type t_row_status_arr is table of eba_cm_checklist_rows.row_status%type index by pls_integer;
type t_percent_complete_arr is table of number index by pls_integer;
l_rid_arr t_rid_arr;
l_row_status_arr t_row_status_arr;
l_percent_complete_arr t_percent_complete_arr;
begin
SELECT
rid,
row_status,
eba_cm_checklist_std.get_row_percent_complete(pc.id,pc.checklist_id,pc.max_col_num) AS percent_complete
bulk collect into
l_rid_arr,
l_row_status_arr,
l_percent_complete_arr
FROM (
SELECT r.rowid as rid,
r.*,
count(*) over(partition by checklist_id) AS max_col_num
FROM eba_cm_checklist_rows r
) pc;
forall i in 1..l_rid_arr.count
update eba_cm_checklist_rows
set row_status = case when l_percent_complete_arr(i) = 100 then 'Green' else row_status end
where rowid = l_rid_arr(i);
end;
/
you could try to use CTE and SUM() OVER() function, hope you find it useful.
Try something like this:
merge into eba_cm_checklist_rows trg
using (
SELECT
rid,
checklist_id,
row_status,
eba_cm_checklist_std.get_row_percent_complete(pc.id,pc.checklist_id,pc.max_col_num) AS percent_complete
FROM
(
SELECT r.rowid as rid,
r.*,
count(*) over(partition by checklist_id) AS max_col_num
FROM eba_cm_checklist_rows r
) pc
) src
on (trg.rowid = src.rid)
when matched then update set row_status = 'Green' where percent_complete = 100;
I don't like the idea to use function inside the SQL - it's probably could be replaced with normal SQL.

In SQL Server, how to create while loop

I Have the following :
I used the select to got the Id from table as follow :
Select Id from t
data will be like this:
id
DG1
FS2
DD4
I want to pass result the result to the following sql statement using while or case
Depend of the result of the select statement
SELECT f.age_days, f.Body_wt,f.Act_Fcr_Day,f.Act_Growth ,
f.growth_gm as Growth ,f2.growth_gm as Growth1,
COALESCE(
(
SELECT TOP 1 Body_wt
FROM [dbo].[Broiler_Farms_Data] mi
WHERE mi.Age_Days > f.Age_Days and mi.flock_id = ??????
ORDER BY
Age_Days
), 0) - f.Body_wt AS diff
FROM [dbo].[Broiler_Farms_Data] f
How can I do it .
thanks
I find this type of logic easier to follow with outer apply:
SELECT f.age_days, f.Body_wt, f.Act_Fcr_Day, f.Act_Growth,
f.growth_gm as Growth, f2.growth_gm as Growth1,
(COALESCE(mi.Body_wt, 0) - f.Body_wt0 AS diff
FROM [dbo].[Broiler_Farms_Data] f OUTER APPLY
(SELECT TOP 1 mi.*
FROM [dbo].[Broiler_Farms_Data] mi
WHERE mi.Age_Days > f.Age_Days and mi.flock_id = ??????
ORDER BY mi.Age_Days
) mi;
Then, if I understand correctly:
SELECT t.id, f.age_days, f.Body_wt, f.Act_Fcr_Day, f.Act_Growth,
f.growth_gm as Growth, f2.growth_gm as Growth1,
(COALESCE(mi.Body_wt, 0) - f.Body_wt0 AS diff
FROM [dbo].[Broiler_Farms_Data] f CROSS JOIN
(Select Id from t
) t OUTER APPLY
(SELECT TOP 1 mi.*
FROM [dbo].[Broiler_Farms_Data] mi
WHERE mi.Age_Days > f.Age_Days and mi.flock_id = t.id
ORDER BY mi.Age_Days
) mi;
This also includes the id in the SELECT, because that seems desirable.
Aggregate functions in VARCHAR columns are not advised. If you have a Primary Key or a surrogate key which can be used, then it will be helpful. Use the below query to use WHILE LOOP.
DECLARE #Id VARCHAR(10) = ''
WHILE 1=1
BEGIN
SELECT #Id = MIN(Id) from t WHERE Id > #Id
IF #Id IS NULL
BREAK
SELECT f.age_days, f.Body_wt,f.Act_Fcr_Day,f.Act_Growth ,
f.growth_gm as Growth ,f2.growth_gm as Growth1,
COALESCE(
(
SELECT TOP 1 Body_wt
FROM [dbo].[Broiler_Farms_Data] mi
WHERE mi.Age_Days > f.Age_Days and mi.flock_id = #Id
ORDER BY
Age_Days
), 0) - f.Body_wt AS diff
FROM [dbo].[Broiler_Farms_Data] f
END

rank over in mysql

I read this article, and i have the code in oracle, but I want to convert it to work on MySQL. In Oracle, i use the function rank, with four columns can eligible or not, how i can use this in mysql, or, it is not possible?
This is the code, I want select the most eligible line, every line can have 4 columns completed, I want to rank one of which has more data.
SELECT vlr,
data
INTO vn_vlr,
vd_data
FROM (SELECT a.*, rank() over (ORDER BY nvl(a.id_categoria, -1) DESC,
nvl(a.id_peso, -1) DESC,
nvl(a.id_faixa, -1) DESC,
nvl(a.sexo, ' ') DESC ) rank
FROM tab_regra_pagamento a
WHERE a.id_competicao = pidcompedticao
AND a.tipo = 'NORMAL'
AND a.data_vencimento > SYSDATE
AND nvl(a.id_categoria, vid_categoria) = vid_categoria
AND nvl(a.id_faixa, vid_faixa) = vid_faixa
AND nvl(a.id_peso, vid_peso) = vid_peso
AND nvl(a.sexo, vsexo) = vsexo)
WHERE rank = 1;
SELECT #rank := #rank + (#value <> value),
#value := value
FROM (
SELECT #rank := 0,
#value := -1
) vars,
mytable
ORDER BY
value
In you case, when you just need all copies of the first set of values:
SELECT vlr, data
FROM tab_regra_pagamento a
WHERE a.id_competicao = pidcompedticao
AND a.tipo = 'NORMAL'
AND a.data_vencimento > SYSDATE
AND (a.id_cetegoria, a.id_faixa, a.id_peso, a.sexo) =
(
SELECT ai.id_cetegoria, ai.id_faixa, ai.id_peso, ai.sexo
FROM tab_regra_pagamento ai
WHERE ai.id_competicao = pidcompedticao
AND ai.tipo = 'NORMAL'
AND ai.data_vencimento > SYSDATE
ORDER BY
a.id_cetegoria DESC, a.id_faixa DESC, a.id_peso DESC, a.sexo DESC
LIMIT 1
)