I have a list of products which have an ID column as primary key, and category id which is a foreign key.. I want to overthem by a certain way.
ID | Name | CategoryID
----------------------------
1 | one | 1
2 | two | 2
3 | three | 1
4 | four | 3
5 | five | 5
6 | six | 4
7 | seven | 2
8 | eight | 1
if the above is my table. I want to get them in an SQL like the folowing
if want order these products in a certain way where all the products of category 5 needs to be
appearing first I am running a query like this.
SELECT * FROM Product ORDER BY CategoryID IN (5), ID
this does the job well.
but now i am in need to show the category id 5 first and then category id 2 first and the rest
if I try
SELECT * FROM Product ORDER BY CategoryID IN (5), CategoryID IN (2), ID ASC
that doesnt work.
any suggestions
You can use MySQL's FIELD() function:
SELECT * FROM Product ORDER BY FIELD(CategoryID, 2, 5) DESC
See it on sqlfiddle.
Try this way:
SELECT * FROM Product
ORDER BY
case CategoryID
when 5 then 0
when 2 then 1
else 2
end
, ID
Related
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.
I have some problem to get the ID which use on another table row. I have three tables. One is category, articles, video. In articles and video there is a column which have category ID. This is the example:
Table Categories :
id | category_name
------------------
1 | News
2 | Sports
3 | Art
4 | Horror
Table Articles :
id | category_id | title
----------------------------------
1 | 1 | title content 1
2 | 1 | title content 2
3 | 3 | title content 3
4 | 3 | title content 4
5 | 2 | title content 5
Table Video :
id | category_id | video_title
------------------------------
1 | 1 | video title 1
2 | 2 | video title 2
3 | 3 | video title 3
I want to get each category ID already use what time in two other databases. Like this :
Category ID 1 is use 3 times
Category ID 2 is use 2 times
Category ID 3 is use 3 times
Category ID 4 is use 0 times
What query do I need to use so I can get all data like that ? Please anyone knows could help me. Thanks in advance.
First you need to UNION ALL articles table and video table be a subquery, then use Outer join and COUNT function.
SELECT Concat('Category ID ', c.id, ' is use ', Count(t.category_id ), ' times')
FROM categories c
LEFT JOIN (SELECT category_id
FROM articles
UNION ALL
SELECT category_id
FROM video) t
ON c.id = t.category_id
GROUP BY c.id
SQLFIDDLE:http://sqlfiddle.com/#!9/92cbd0e/12
[Results]:
| Concat('Category ID ', t.id, ' is use ', t.cnt, ' times') |
|------------------------------------------------------------|
| Category ID 1 is use 3 times |
| Category ID 2 is use 2 times |
| Category ID 3 is use 3 times |
| Category ID 4 is use 0 times |
NOTE
COUNT function does not count numbers if the column value encounters null
For example Here is a sample script.
CREATE TABLE T(
col int
);
INSERT INTO T VALUES (NULL);
INSERT INTO T VALUES (1);
SELECT COUNT(col) FROM t; -- RESULT = 1
SELECT COUNT(*) FROM t; --RESULT = 2
sample sqlfiddle:http://sqlfiddle.com/#!9/e2bba7/2
You can use, for example, this query:
Select category_id, count(1) - 1
From (
Select category_id From video
Union All Select category_id From articles
Union All Select id From Categories)
Group By category_id
Ok, this should be simple:
ID | version | downloads
========================
1 | 1.0 | 2
1 | 1.1 | 4
1 | 1.2 | 7
1 | 1.3 | 3
2 | 1.0 | 3
2 | 2.0 | 3
2 | 3.0 | 13
I like to get the downloads of a specific product (ID) no matter which version.
This doesn't work
SELECT COUNT(*) AS downloads FROM table WHERE ID = 1
should return 2 + 4 + 7 + 3 = 16
Your output says that you want to sum the downloads column.
so you have to use sum aggregate function..
SELECT Sum(downloads) AS downloads FROM table WHERE ID = 1
If you want sum(downloads) for each ID,Just change the query as follow
SELECT ID,Sum(downloads) AS downloads FROM table group by ID
If you need total record counts then only use Count
SELECT Count(*) AS count FROM table WHERE ID = 1
SELECT SUM(downloads) FROM table WHERE ID = 1;
Try
SELECT SUM(downloads) AS downloads
FROM table
WHERE id = 1
Sum adds the values
You can also use group by to return the sum for each id
SELECT SUM(downloads) AS downloads
FROM table
GROUP BY id
I would go for a query that could show you all SUMs from all IDs then if you need you filter one in specific.
SELECT id,
SUM(downloads) as TotalDownloads
FROM table
GROUP BY id;
If you need to filter a specific id just add where id = 1
The result for this would be:
ID | TotalDownloads
========================
1 | 16
2 | 19
I am fetching all stations which belong to a station group from my database. SELECT * FROM stations WHERE station_group_id = 1.
Now, from all the fetched results, I want certain ones to appear first (e.g. the stations which have line_id = 2 to appear first). For example, if this is my stations table:
id | station_group_id | line_id
-------------------------------
1 | 1 | 1
2 | 1 | 2
3 | 1 | 3
I would like the output to be:
id | station_group_id | line_id
-------------------------------
1 | 1 | 2
2 | 1 | 1
3 | 1 | 3
So that line_id = 2 is the first record in the output.
I thought about using ORDER BY, but it isn't quite an order issue, it is more a "preference" one.
So, is it possible to place some records on top of the output, based on a condition, preferably in one query? Thanks!
Try Below:
SELECT * FROM stations
WHERE station_group_id = 1
ORDER BY if(line_id in('2','X','Y','Z'),0,1)
SELECT * FROM stations WHERE station_group_id = 1 and line_id = 2
union
SELECT * FROM stations WHERE station_group_id = 1 and
line_id != 2 order by line_id asc
As you are saying, it is actually a preference, so you should either model it as an extra field on the table (e.g. ordinal, or order, or preferredOrder), or you keep sorting by line_id, and do the "special sort" in code. (find element with id=2, move to top)
I've a table with the following structure:
id | property_id | location_type
1 | 1 | 1
2 | 1 | 2
3 | 2 | 1
4 | 3 | 2
5 | 4 | 1
6 | 4 | 2
id - is the primary key of the table. property_id is the property ID of my database (foreign key). location_type is beach (value - 1), mountain (value - 2)
Can you please help me in getting the SQL query to select the property_id with location_type = 1 AND location_type = 2 i.e. a property has beach and mountains.
I have lot of filters (around 9 types of location_type and other filters). I'm creating a property search engine with filters. Please help in getting the most optimized query so load time is less.
select
property_id
from table
where location_type in (1,2)
group by property_id
having count(distinct(location_type)) = 2
if you don't have duplicates you can remove distinct clause.
A self-join would eliminate the need for a subquery, although that doesn't mean that it will be faster; normal profiling rules apply:
SELECT table1.property_id
FROM table table1
INNER JOIN table tabel2 ON table1.property_id = table2.property_id
WHERE table1.location_type = 1
AND table2.location_type = 2