Select one fixed line and several arbitrary - mysql

I have a table with many lines. I need select several (no more than three) lines with certain values and one more. Moreover, need ORDER BY id DESC and required line position before other. Example:
id | name | group
-----------------
1 | One | null
2 | Two | null
3 | Three| 2
4 | Four | 3
5 | Five | 1
6 | Six | 2
I need lines with group == 2 (no more than three) and line with id == 2. Result:
id | name | group
-----------------
2 | Two | null
3 | Three| 2
6 | Six | 2
Line with id == 2 must be selected, other lines - no more than three. If I use WHERE id = 2 OR group = 2 LIMIT 4 than if exist more than 4 lines with group == 2, then required line with id == 2 not selected.
How solve the problem in one SQL-request?

You can try using UNION. Also note that group is a reserved word for MySQL.
SELECT aa.*
FROM (
SELECT id, firstname, lastname
FROM user
WHERE id IN (1, 2, 3, 4)
LIMIT 2
UNION ALL
SELECT id, firstname, lastname
FROM user
WHERE id = 5
) AS aa

select * from table_name where id=2
union all
select * from table_name where group=2

Related

MySQL - select distinct value from two column

I have a table with the following structure:
IdM|IdS
-------
1 | 2
1 | 3
1 | 4
2 | 1
2 | 3
2 | 4
3 | 1
3 | 2
3 | 3
3 | 4
How could I make a select statement on this table, which will return some rows of this table, where in each row, a specific id appears only one, indifferent on which column it is specified?
For the above result set, I would like a query that would return:
-------
1 | 2
3 | 4
-------
To give another example, if you would omit the first row in the original dataset:
IdM|IdS
-------
1 | 3
1 | 4
2 | 1
2 | 3
2 | 4
3 | 1
3 | 2
3 | 3
3 | 4
the result set should be:
-------
1 | 3
2 | 4
-------
That's actually an interesting problem. If I follow you correctly, you want to iterate through the dataset and only retain rows where both values were never seen before. You could use a recursive query:
with recursive
data as (
select idm, ids, row_number() over(order by idm, ids) rn
from mytable
where idm <> ids
),
cte as (
select idm, ids, rn, 1 as to_keep , concat(idm, ',', ids) visited from data where rn = 1
union all
select d.idm, d.ids, d.rn,
(not find_in_set(d.idm, c.visited) and not find_in_set(d.ids, c.visited)),
case when (not find_in_set(d.idm, c.visited) and not find_in_set(d.ids, c.visited))
then concat_ws(',', c.visited, d.idm, d.ids)
else c.visited
end
from cte c
inner join data d on d.rn = c.rn + 1
)
select idm, ids from cte where to_keep
The first CTE enumerates the rows ordered by both columns. Then the recursive query walks the resultset, checks if both values are new, and sets a flag accordingly of the columns. Flagged numbers are retained to be used for filtering in the following iteration.
Demo on DB Fiddle
Note that, given your requirement, not all values may appear in the resultset. Consider the following dataset:
idm ids
+-----+---
1 2
1 3
1 4
Your logic will only return the first row.

How to select one row each conditions in MySQL?

I have a trouble with my code. I want to get only one rows each conditions in MySQL.
I have a table like that:
ID - Position - Content
1 2 abc
2 1 def
3 1 ghk
4 3 pol
5 2 lop
6 4 gty
So I want the result returned like: position = 1 -> highest id row then pass to position = 2 -> highest id row. I have no idea to code it.
Use a sub query to test the id
drop table if exists t;
create table t
(ID int, Position int, Content varchar(3));
insert into t values
(1 , 2 , 'abc'),
(2 , 1 , 'def'),
(3 , 1 , 'ghk'),
(4 , 3 , 'pol'),
(5 , 2 , 'lop'),
(6 , 4 , 'gty');
select t.*
from t
where t.id = (select min(id) from t t1 where t1.position = t.position);
+------+----------+---------+
| ID | Position | Content |
+------+----------+---------+
| 1 | 2 | abc |
| 2 | 1 | def |
| 4 | 3 | pol |
| 6 | 4 | gty |
+------+----------+---------+
4 rows in set (0.00 sec)
try this query..
SELECT DISTINCT * FROM table-name ORDER BY ID ASC;
DISTINCT operates on a single column. DISTINCT for multiple columns is not supported.
same column cant not print
And
order by id asc use and all record print 1 - n means minimum id
you can try like below query
SELECT t.*
FROM t
WHERE t.id IN (SELECT min(id) FROM t GROUP BY position);

Mysql IN function

class_table
+----+-------+--------------+
| id |teac_id| student_id |
+----+-------+--------------+
| 1 | 1 | 1,2,3,4 |
+----+-------+--------------+
student_mark
+----+----------+--------+
| id |student_id| marks |
+----+----------+--------+
| 1 | 1 | 12 |
+----+----------+--------+
| 2 | 2 | 80 |
+----+----------+--------+
| 3 | 3 | 20 |
+----+----------+--------+
I have these two tables and i want to calculate the total marks of student and my sql is:
SELECT SUM(`marks`)
FROM `student_mark`
WHERE `student_id` IN
(SELECT `student_id` FROM `class_table` WHERE `teac_id` = '1')
But this will return null, please help!!
DB fiddle
Firstly, you should never store comma separated data in your column. You should really normalize your data. So basically, you could have a many-to-many table mapping teacher_to_student, which will have teac_id and student_id columns.
In this particular case, you can utilize Find_in_set() function.
From your current query, it seems that you are trying to getting total marks for a teacher (summing up marks of all his/her students).
Try:
SELECT SUM(sm.`marks`)
FROM `student_mark` AS sm
JOIN `class_table` AS ct
ON FIND_IN_SET(sm.`student_id`, ct.`student_id`) > 0
WHERE ct.`teac_id` = '1'
In case, you want to get total marks per student, you would need to add a Group By. The query would look like:
SELECT sm.`student_id`,
SUM(sm.`marks`)
FROM `student_mark` AS sm
JOIN `class_table` AS ct
ON FIND_IN_SET(sm.`student_id`, ct.`student_id`) > 0
WHERE ct.`teac_id` = '1'
GROUP BY sm.`student_id`
Just in case you want to know why, The reason it returned null is because the subquery returned as '1,2,3,4' as a whole. What you need is to make it returned 1,2,3,4 separately.
What your query returned
SELECT SUM(`marks`)
FROM `student_mark`
WHERE `student_id` IN ('1,2,3,4')
What you expect is
SELECT SUM(`marks`)
FROM `student_mark`
WHERE `student_id` IN (1,2,3,4)
The best way is it normalize as #madhur said. In your case you need to make the teacher and student as one to many link
+----+-------+--------------+
| id |teac_id| student_id |
+----+-------+--------------+
| 1 | 1 | 1 |
+----+-------+--------------+
| 2 | 1 | 2 |
+----+-------+--------------+
| 3 | 1 | 3 |
+----+-------+--------------+
| 4 | 1 | 4 |
+----+-------+--------------+
If you want to filter your table based on a comma separated list with ID, my approach is to
append extra commas at the beginning and at the end of a list as well as at the beginning and at the end of an ID, eg.
1 becomes ,1, and list would become ,1,2,3,4,. The reason for that is to avoid ambigious matches like 1 matches 21 or 12 in a list.
Also, EXISTS is well-suited in that situation, which together with INSTR function should work:
SELECT SUM(`marks`)
FROM `student_mark` sm
WHERE EXISTS(SELECT 1 FROM `class_table`
WHERE `teac_id` = '1' AND
INSTR(CONCAT(',', student_id, ','), CONCAT(',', sm.student_id, ',')) > 0)
Demo
BUT you shouldn't store related IDs in one cell as comma separated list - it should be foreign key column to form proper relation. Joins would become trivial then.

Mysql group concat with counting items

I have 2 tables, 'item' and 'propvalues', propvalues have property_id and value column, what im trying to get is to group propvalues as property_id, and count how many similar values they have.
i know it is similar to another question, but i was unable to figure out how to change it for myself to work. if someone is good at mysql please dont mark it as a duplicate question, but rather try to give me at least some advice. i dont understand what is going on when there is an inner select statement
Here are the tables:
'item'
id category_id
1 1
2 1
3 2
4 5
etc.
'propvalues'
id item_id property_id value
1 1 3 'blue'
2 1 3 'blue'
3 1 3 'blue'
4 1 3 'red'
5 1 5 'blue'
6 1 5 'red'
7 2 5 'red'
SELECT propvalues.property_id,
GROUP_CONCAT(propvalues.value)
FROM propvalues JOIN item ON item.id = propvalues.item_id
WHERE item.category_id = 1 || item.category_id = 2
GROUP BY propvalues.property_id
this give this result:
property_id value
3 blue,blue,blue,red
5 blue,red,red
but i need this, result, i want only the unique values,and count them:
3 blue,3|red,1
5 blue,1|red,2
any ideas ?
i found some solution here: mysql group_concat with a count inside?
but im unable to figure out how to change it for myself to work.
Derived from the refered duplicate:
SELECT property_id, GROUP_CONCAT(CONCAT(value, ',', cnt) SEPARATOR '|')
FROM (
SELECT property_id, value, COUNT(value) AS cnt
FROM propvalues
JOIN item ON item.id = propvalues.item_id
AND item.category_id IN (1, 2)
GROUP BY property_id, value
) t
GROUP BY property_id
To break it down, the inner subquery fetches a number of distinct values per property_id:
+-------------+-------+-----+
| property_id | value | cnt |
+-------------+-------+-----+
| 3 | blue | 3 |
| 3 | red | 1 |
| 5 | blue | 1 |
| 5 | red | 2 |
+-------------+-------+-----+
The outer main query further aggregates theses values by distinct property_id, concatenates value and count to a string (CONCAT(value, ',', cnt)) and then concatenates those from each row (GROUP_CONCAT(... SEPARATOR '|')).

SQL: Count distinct row values in table

I have a similar table to this in SQL:
id |tag | entryID
---+----+--------
1 |foo | 0
2 |foo | 0
3 |bar | 3
5 |bar | 3
6 |foo | 3
7 |foo | 3
I want to run a query to count distinct rows in the table (with the id column dropped). The result should look like this (or a transpose of this table):
(tag=foo, entryID=0) | (tag=foo, entryID=3) | (tag=bar, entryID=3)
---------------------+----------------------+---------------------
2 | 2 | 2
What should this query look like?
Note: The values in each of the columns are not known beforehand.
You can do this using conditional aggregation:
select sum(tag = 'foo' and entryId = 0) as "tag=foo, entryID=0",
sum(tag = 'foo' and entryId = 3) as "tag=foo, entryID=3",
sum(tag = 'bar' and entryId = 3) as "tag=bar, entryID=0"
from t;
However, the normal method is to put the counts in rows, not columns:
select tag, entryId, count(*)
from t
group by tag, entryId;
The rows are much more versatile, because you don't have to list out every combination you might want to match.