I need to fill the group_concat with values, no more no less than 4 values, if there is more, create another row of the next 4 until there is no more.
I have this:
cd_table
GROUP_CONCAT
1
A04,A01,A00
2
A01
I need this:
cd_table
GROUP_CONCAT
1
A04,A01,A00,false
2
A01,false,false,false
3
A04,A01,A00,A03
3
A02,false,false,false
Fiddle: http://sqlfiddle.com/#!9/51b601/3/0
There are several components to this:
Limiting the ids to four per row.
Adding additional rows.
Adding the falses.
This can be incorporated into a query:
SELECT cd_guime,
SUBSTRING_INDEX(CONCAT(GROUP_CONCAT(ds_tbcid), ',false,false,false'), ',', 4)
FROM (SELECT guime.cd_guime, ds_tbcid,
ROW_NUMBER() OVER (PARTITION BY guime.cd_guime ORDER BY ds_tbcid) as seqnum
FROM guime JOIN
gucid
ON gucid.cd_guime = guime.cd_guime JOIN
tbcid
ON gucid.cd_tbcid = tbcid.cd_tbcid
) x
GROUP BY cd_guime, CEILING(seqnum / 4.0);
Here is a db<>fiddle.
Related
In the following, I am querying the same table 2 times. The second query is a nested query inside left join but queries the same table. The only difference is the addition of the aggregation function count, the result of which is used by the outer query. Is there a better way to approach this?
select sm.student_id, sm.marks, smarks.d as d_marks from student_marks as sm
left join(
select m.student_id, count(distinct m.marks) as d from student_marks as m group by m.student_id
) as smarks on smarks.student_id = sm.student_id;
Is it possible to do this in a single query without using a left join.
Yes there is an alternative approach which is using windowed functions. There's no way of doing COUNT(DISTINCT in a windowed function, but you can do this using DENSE_RANK() twice, once sorting by what you want a distinct count of ascending, and once descending, adding these together then taking one away:
SELECT sm.student_id,
sm.marks,
DENSE_RANK() OVER(PARTITION BY sm.student_id ORDER BY sm.marks DESC) +
DENSE_RANK() OVER(PARTITION BY sm.student_id ORDER BY sm.marks ASC) - 1 AS d_marks
FROM student_marks AS sm
N.B. this is not guaranteed to perform any better just because you are referencing a table one fewer times.
To explain the DENSE_RANK() trick, consider a simple data set:
marks
dense_rank ASC
dense_rank DESC
1
1
3
1
1
3
2
2
2
3
3
1
The two ranks added together will always be one more than the total number of items in the set (i.e. 1+3, 2+2, and 3+1 all equal 4), so we just need to take one off the result and this gives us our distinct count of items in the set without actually using COUNT(DISTINCT which isn't allowed (as noted in the restrictions)
ADENDUM
If marks is nullable (which I had assumed it would not be) and you don't want null rows included in the count, then as noted in the comments this wouldn't quite work as it is, you'd need to remove any null rows from the total, which can be done using:
- MAX(CASE WHEN sm.marks IS NULL THEN 1 ELSE 0 END) OVER(PARTITION BY sm.student_id)
SELECT COUNT('2018-02-12')
as ids FROM tg_partner_data
WHERE assign_to = '2'
AND
followup_date = '2018-02-12' AND active='Y'
LIMIT (SELECT count FROM tg_master_count WHERE count_for = 'followup')
I tried to get count as output but this query doesnot works . I am using like this because the limit setting is dynamic.
An immediate problem with your use of LIMIT is that you have no ORDER BY clause. Which first records do you expect from the result set? This is not clear. I will give a generic pattern which you can use to have a subquery limit the number of records.
Consider a simple table with just one column:
col
1
2
3
4
5
Now let's say that you want to limit the number of records in the result set, based on an ordering of col, using some subquery. We can write the following:
SET #rn=0;
SELECT col
FROM
(
SELECT
col,
#rn:=#rn+1 rn
FROM yourTable
ORDER BY
col
) t
WHERE t.rn <= (SELECT 3 FROM dual); -- replace with your own subquery
Demo
The basic idea here is that we simulate row number in a subquery, that is, we assign a row number to each record, ordered according the the col column. Then we subquery that table, and retain only records matching the subquery you want to use to limit.
I have 2 columns having users id participating in a transaction, source_id and destination_id. I'm building a function to sum all transactions grouped by any user participating on it, either as source or as destination.
The problem is, when I do:
select count (*) from transactions group by source_id, destination_id
it will first group by source, then by destination, I want to group them together. Is it possible using only SQL?
Sample Data
source_user_id destination_user_id
1 4
3 4
4 1
3 2
Desired result:
Id Count
4 - 3 (4 appears 3 times in any of the columns)
3 - 2 (3 appears 2 times in any of the columns)
1 - 2 (1 appear 2 times in any of the columns)
2 - 1 (1 appear 1 time in any of the columns)
As you can see on the example result, I want to know the number of times an id will appear in any of the 2 fields.
Use union all to get the id's into one column and get the counts.
select id,count(*)
from (select source_id as id from tbl
union all
select destination_id from tbl
) t
group by id
order by count(*) desc,id
edited to add: Thank you for clarifying your question. The following isn't what you need.
Sounds like you want to use the concatenate function.
https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_concat
GROUP BY CONCAT(source_id,"_",destination_id)
The underscore is intended to distinguish "source_id=1, destination_id=11" from "source_id=11, destination_id=1". (We want them to be 1_11 and 11_1 respectively.) If you expect these IDs to contain underscores, you'd have to handle this differently, but I assume they're integers.
It may look like this.
Select id, count(total ) from
(select source_id as id, count (destination_user_id) as total from transactions group by source_id
union
select destination_user_id as id , count (source_id) as total from transactions group by destination_user_id ) q group by id
I have a mysql table with schema as follows:
group id amount fraction
1 1 3
1 2 5
2 3 2
2 3 1
Each of the rows belongs to a group. Each row also stores a specific value called amount. I want to find the fraction of the group total amount that each row has, so the table will look like this:
AFTER
group id amount fraction
1 1 3 .375
1 2 5 .625
2 3 2 66.67
2 3 1 33.33
To get the value for column 1, I sum up all the amount columns in group 1. That would be 3+5, which is 8. Then I divide the amount in row 1 by the group sum, which yields .375. I do this for all of them.
I could do this by writing query like so:
SELECT SUM(amount) GROUP BY group
Then loop through each group, select rows in that group, calculate fractions, and update the rows. Unfortunately this means that after the initial query I will be dealing with 2 nested for loops, and millions and millions of queries, which will take a long time given the size of the dataset.
I have a subtle feeling that there is a way to do this more efficiently with one mysql query. If anybody has any ideas how to do this with a single query, that's my question.
You can do this in a single query with a join and aggregation:
select t.*, t.amount / tt.sumamount
from t join
(select group, sum(amount) as sumamount
from t
group by group
) tt
on t.group = tt.group;
EDIT:
The update is quite similar:
update t join
(select group, sum(amount) as sumamount
from t
group by group
) tt
on t.group = tt.group
set fraction = t.amount / tt.sumamount;
I need to show ordered 20 records on my grid but I can't use LIMIT because of my generator(Scriptcase) using LIMIT to show lines per page. It's generator's bug but I need to solve it for my project. So is it possible to show 20 ordered record from my table with a query?
As from comments,if you can't use limit then you can rank your results on basis of some order and in parent select filter limit the results by rank number
select * from (
select *
,#r:=#r + 1 as row_num
from your_table_name
cross join (select #r:=0)t
order by some_column asc /* or desc*/
) t1
where row_num <= 20
Demo with rank no.
Another hackish way would be using group_concat() with order by to get the list of ids ordered on asc/desc and substring_index to pick the desired ids like you need 20 records then join with same table using find_in_set ,But this solution will be very expensive in terms of performance and group_concat limitations if you need more than 20 records
select t.*
from your_table_name t
join (
select
substring_index(group_concat(id order by some_column asc),',',20) ids_list
from your_table_name
) t1 on (find_in_set(t.id , t1.ids_list) > 0)
Demo without rank
What about SELECT in SELECT:
SELECT *
FROM (
-- there put your query
-- with LIMIT 20
) q
So outer SELECT is without LIMIT and your generator can add own.
In a Scriptcase Grid, you CAN use Limit. This is a valid SQL query that selects only the first 20 records from a table. The grid is set to show only 10 records per page, so it will show 20 results split in a total of 2 pages:
SELECT
ProductID,
ProductName
FROM
Products
LIMIT 20
Also the embraced query works out well:
SELECT
ProductID,
ProductName
FROM
(SELECT
ProductID,
ProductName
FROM Products LIMIT 20) tmp