How to order data from database by user choice - php

Say i have this table :
---------+----------
name | id
---------+----------
apple | 1
orange | 2
book | 3
notebook | 4
textboo | 5
phone | 6
if the user want to sort this table as he want ..
not order them as id or name .. order them as he want to show them ..
How to make something like that ?
Can we do them by java or jquery or something else
if user want to display orange | 2 then phone | 6
then the other values or want to display notebook | 4 first then other values how we can control something like that ?

Suppose you have multiple users you will need to create a new table where you will save each user's sort order preferences.
---------+-------------------
item_id | user_id | sort
---------+------------------
1 | 1 | 2
2 | 1 | 1
3 | 1 | 3
After that you can easily use ORDER BY in your query to fetch the order chosen by the user based on his user_id. If you're looking for user_id = 1, the following query should work:
SELECT * FROM `table1` t1
LEFT JOIN `preferences_table` PT ON PT.item_id = t1.id
WHERE user_id = 1
ORDER BY PT.sort ASC

Related

How to select specific course by selecting course id and concatenate users all selected course with in same row

I am joining users table with selected_course table and course table with selected_course, my requirement is I want to get those users with course_id=2 and in same row select using concatenation of all courses which is selected by user.
user table
id name
1 user_1
2 user_2
user_education_details
id user_id education_id selected_course
1 1 1 2
2 2 1 2
3 1 2 4
4 3 1 2
5 3 2 4
Actual Requirement:
user_id required_course user_all_courses course_name
1 2 2,4 a,b
2 2 2 a
3 2 2,4 a,b
Using codeigniter query format:
$this->db->select('users.*');
$this->db->from('users');
$this->db->join('selected_course sc','c.user_id=users.id');
$this->db->join('course c','c.id=sc.selected_course');
$this->db->where('sc.selected_course',$course_id=2);
$this->db->get()->result();
A HAVING clause is what you're looking for. To filter data based on a group use this clause.
SELECT
ued.user_id,
2 AS required_course, -- passed course id
GROUP_CONCAT(ued.selected_course) AS user_all_courses,
GROUP_CONCAT(c.name) course_name
FROM user_education_details ued
INNER JOIN courses c ON ued.selected_course = c.id
GROUP BY user_id
HAVING SUM(IF(selected_course = 2, 1,0)) > 0;
Output:
| user_id | required_course | user_all_courses | course_name |
| 1 | 2 | 4,2 | b,a |
| 2 | 2 | 2 | a |
| 3 | 2 | 2,4 | a,b |
You can also order user_all_courses and course_name by using a ORDER BY clause inside GROUP_CONCAT. Here is one example.
GROUP_CONCAT(ued.selected_course ORDER BY selected_course ASC) AS user_all_courses,
Now you can quickly convert this to your equivalent CodeIgniter query.
Check this working fiddle for the same.

laravel recursion display referred users by level/depth

So I'm working with affiliate and doing fine with registration and saving who referred to a user,
now I'm struggling in showing those users with referrals by Level.
Level is not save in the database, I'm thinking of it as incrementing in the logic area?
users table structure
id | name | sponsor_id |
1 | John | NULL |
2 | Jane | 1 |
3 | Jess | 1 |
4 | Joe | 2 |
so the output I want should be like this:
I am John, level 1 are who's sponsor_id is mine, and level 2 are who's sponsor_id is id's of whom I invited.
ID | Name | Level |
2 | Jane | 1 |
3 | Jess | 1 |
4 | Joe | 2 |
where Jane & Jess's sponsor_id is mine, and Joe's sponsor_id is Jess
User has sponsor
public function sponsor()
{
return $this->belongsTo('App\User', 'sponsor_id');
}
User has referrals
public function referrals()
{
return $this->hasMany('App\User', 'sponsor_id');
}
If MySQL 8 (very advised with hierarchical data like yours), you can do this with a recursive CTE :
WITH RECURSIVE CTE_users_levels(id, name, level) AS
(
SELECT id, name, 0 as level
FROM users
WHERE sponsor_id IS NULL
UNION ALL
SELECT u.id, u.name, cte.level+1
FROM CTE_users_levels cte
JOIN users u ON cte.id=u.sponsor_id
)
-- To output all users' levels:
SELECT * FROM CTE_users_levels ORDER BY level;
Now you have virtual table containing the level column for all your users and you can query it
| id | name | level |
| --- | ---- | ----- |
| 1 | John | 0 |
| 2 | Jane | 1 |
| 3 | Jess | 1 |
| 4 | Joe | 2 |
DBFiddle
GOing further...
Make a view out of your CTE
CREATE VIEW VIEW_User_Levels AS
(
WITH RECURSIVE CTE_users_levels(id, name, level) AS
(
SELECT id, name, 0 as level
FROM users
WHERE sponsor_id IS NULL
UNION ALL
SELECT u.id, u.name, cte.level+1
FROM CTE_users_levels cte
JOIN users u ON cte.id=u.sponsor_id
)
SELECT * FROM CTE_users_levels ORDER BY level
)
Now it's easy to get all your users levels (no need to have the CTE statement) :
SELECT * FROM VIEW_User_Levels
Then, if you have a lot of users, it's a bit ovekilling to recompute the whole tree all the time (which the VIEW does)
Then you can fix the level of your users in a new column.
ALTER TABLE users ADD level INT;
And populate that column for all users with the help of your view:
UPDATE users u, VIEW_User_Levels v
SET u.level=v.level
WHERE u.id=v.id;
Which gives
SELECT * FROM users
id name sponsor_id level
1 John null 0
2 Jane 1 1
3 Jess 1 1
4 Joe 2 2
DBFiddle
If you have a lot of users, and your aim is to query the level column a lot, INDEX IT.
Note that you can also update the level value of only one user (for instance if its sponsor_id changes, or if the user is new)
UPDATE users u, VIEW_User_Levels v
SET u.level=v.level
WHERE u.id=v.id AND u.name='Jane';

PHP MySQL Query Search with Foreign Key

I have 2 tables in my databases, tb_device and tb_label which contain this for example:
tb_device
id (AI) | type | label | etc
-------------------------------------
1 | A123 | 1 | test
2 | A561 | 3 | test2
3 | A777 | 2 | test3
4 | A222 | 3 | test4
tb_label
id (AI) | label
-------------------
1 | Samsung
2 | Apple
3 | Dell
And I already create CRUD form (PHP) which display tb_devices. And this CRUD has a searching form on each columns. Other columns are working for search, but label columns isn't working because it's contain id from tb_label. I want to search label with label name like samsung, apple, dell, not with number. My code for searching:
$sql = "SELECT *
FROM tb_device a, tb_label b
WHERE
type LIKE '%".#$_POST['type']."%' AND
(a.label=b.id AND b.label LIKE '%".#$_POST['label']."%') AND
etc LIKE '%".#$_POST['etc']."%'
ORDER BY type
";
I try to input dell, but the result:
3 | A777 | 2 | test3
Explanation : dell have id number 3, and the result showing id number 3 from tb_device. Is there any solution to show the correct result?
Sorry for bad english
You missed b.label in your query
$sql = "SELECT a.*, b.label
FROM tb_device a, tb_label b
WHERE
a.type LIKE '%".#$_POST['type']."%' AND
(a.label=b.id AND b.label LIKE '%".#$_POST['label']."%') AND
etc LIKE '%".#$_POST['etc']."%'
ORDER BY a.type
";
I believe you should only have the WHERE for tb_label.label = (your user input variable: Dell)
I believe you want to do a
INNER JOIN tb_label
ON tb_device.label = tb_label.id

Count How many Data in a month based on Criteria

I have 2 tables, master_kategori_project which is contain category of projects and project which is contains how many project in a specific month in a specific year. below is my master_kategori_project table.
id| category_project | description |
1 | Category 1 | descrip 1 |
2 | Category 2 | descrip 2 |
3 | Category 3 | descrip 3 |
and my project table look something like this
id| id_category_project | name_project | start_date |
1 | 1 | Project 1 | 27-01-2017 |
2 | 2 | Project 2 | 29-02-2017 |
i want to make a table that contain chart like this, u can see from the table on january i have 3 projects of kategori 1, 5 projects of kategori 2, 7 projects of kategori 3 and so on
how can i write an query that have something like this? the chart is automatically build by the table itself.
this is my model and i believe i did it wrong, because i can't put the data into the correct month
public function get_kategori_totals($mnth, $year=null)
{
$yr=date('Y');
$select = "
SELECT COUNT(category_project),start_date,category_project
FROM
project
LEFT JOIN
master_kategori_project
ON
project.id_category_project=master_kategori_project.id
WHERE
MONTH(start_date)='$mnth'".
(($year == null)?" AND YEAR(start_date)='$yr' GROUP BY category_project":"AND YEAR(stat_date)='$year' GROUP BY category_project");
return $this->db->query($select);
}
Use below query.
SELECT id_category_project, month(start_date), count(distinct name_project) as project_count
FROM project
WHERE start_date IS NOT NULL AND start_date <> '0000-00-00'
GROUP BY 1,2
ORDER BY 2,1

Php/mysql ranking system - Placement inside a result set ordered by column

In a blog-like website, all the users can "star" a news (= bookmark it, mark it as "favourite").
I have a mysql table for stats.
table_news_stats
id_news
total_stars (int) //Total number of users who starred this news
placement (int)
The placement field is intuitive: if you order all the news by the total_stars field you get each news placement. So, the news with most stars will be number 1, and so on.
So, suppose I have 700 records in my table_news_stats, and for each one I have the id and the total_stars count, how can I update the placement field automatically for each record? Which query is faster/better?
Example of the table_news_stats content:
First record (A):
1-3654-?
Second record (B):
2-2456-?
Third record (C):
3-8654-?
If you order the record by stars count:
the sequence of records is C - A - B
So... the result will be:
First record (A):
1-3654-2
Second record (B):
2-2456-3
Third record (C):
3-8654-1
Clarification:
why would I ever need the placement field at all?
It's pretty simple... the placement field will be populated by a cronjob the first day of every month. Basically it will provide a 'snapshot' of the rank of each news in terms of popularity (as it was at the beginning of the current month). As a consequence, thanks to the placement field, I will have the following information:
"The 1st day of this month the 'top starred' news list was like this:
1- News C
2- NewsA
3- News B "
Then, with a query "SELECT * FROM table_news_stats ORDER BY total_stars DESC" I can obtain the new ranking (in real-time).
As a consequence, I will have the following information:
"At the time the page is loaded, the 'top starred' news list is like this:
1- News A
2- News C
3- News B "
Finally, by comparing the two rankings, I obtain the last piece of information:
"News A has gained a position" +1
"News C has lost a position" -1
"News B has no change in position" +0
If there is a better way of doing this, let me know.
I guess you don't need to update the table just:
SELECT *
FROM table_news_stats
ORDER BY total_stars DESC
But if you want to know the place of each one you can:
SELECT *, IF(#idx IS NULL,#idx:= 1,#idx:= #idx+1)
FROM table_news_stats
ORDER BY total_stars DESC
And if you still need to update something like:
UPDATE table_news_stats
SET placement = FIND_IN_SET(id_news,(SELECT GROUP_CONCAT(t.id_news) FROM (SELECT id_news
FROM table_news_stats
ORDER BY total_stars DESC) t ))
SQLFiddle
Consider the following
mysql> select * from test ;
+------+-------------+-----------+
| id | total_stars | placement |
+------+-------------+-----------+
| 1 | 3 | 0 |
| 2 | 6 | 0 |
| 3 | 7 | 0 |
| 4 | 2 | 0 |
| 5 | 9 | 0 |
| 6 | 2 | 0 |
| 7 | 1 | 0 |
+------+-------------+-----------+
Now using the following you can update the placement as
update test t1 join
(
select *,
#rn:= if(#prev = total_stars,#rn,#rn+1) as rank ,
#prev:= total_stars
from test,(select #rn:=0,#prev:=0)r
order by total_stars desc
)t2
on t2.id = t1.id
set t1.placement = t2.rank ;
mysql> select * from test order by placement ;
+------+-------------+-----------+
| id | total_stars | placement |
+------+-------------+-----------+
| 5 | 9 | 1 |
| 3 | 7 | 2 |
| 2 | 6 | 3 |
| 1 | 3 | 4 |
| 4 | 2 | 5 |
| 6 | 2 | 5 |
| 7 | 1 | 6 |
+------+-------------+-----------+
Note that in case of tie will have the same placement.

Categories