Most Required Item from mysql with php - php

I have db table structure like that :
--
-- Table structure for table `table_submissions`
--
CREATE TABLE IF NOT EXISTS `table_submissions` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Submission ID',
`item_name` bigint(20) unsigned NOT NULL COMMENT 'Item Name',
`status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0 = pending, 1 = approved, -1 = denied',
PRIMARY KEY (`id`),
KEY `item_name` (`item_name`),
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;
php
$date_info = $db->fetchOne("SELECT * FROM table_submissions");
I need to code php for "Most Required Item" order by count item_name limit 10
This mean the most item_name which the visitor has been required it will be in the top then ++ 9
How i can do that please ?

I believe you want this:
SELECT
item_name,
count(1)
FROM
table_submissions
GROUP BY
item_name
ORDER BY
count(1) DESC
LIMIT 10;
Note this does not take into account one user requesting the same item 1000 times verses 1000 users requesting an item once each. If that's important to you then you need a way to filter by user ID.

Related

Users ranking table on how many likes/upvotes users had

I'm trying to create a ranking table based on how many likes/upvotes a user had on all his items in total. User in the upvotes table links to id of the user that made the like, but I think you don't need this.
Hopefully by giving these tables everything will get clear.
I think the trick here is to get all the upvotes by each item and merge them together towards a user this item was from to get a total likes for each user and then rank all the users based on this total. Of course doing this will probably be a slow query so I need a very performant way to handle this.
The hard thing is here mainly that the upvotes table doesn't include the user id.
3 tables:
CREATE TABLE `items` (
`id` int(255) NOT NULL AUTO_INCREMENT,
`user_id` int(255) NOT NULL,
`img` varchar(500) NOT NULL,
`message` varchar(200) NOT NULL,
`created_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`active` int(11) NOT NULL DEFAULT '1',
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=19 DEFAULT CHARSET=latin1;
CREATE TABLE `upvotes` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user` int(255) NOT NULL,
`item_id` int(255) NOT NULL,
`created_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=latin1;
CREATE TABLE `users` (
`id` int(255) NOT NULL AUTO_INCREMENT,
`email` varchar(255) NOT NULL,
`password` binary(60) NOT NULL,
`first_name` varchar(255) NOT NULL,
`last_name` varchar(255) NOT NULL,
`active` int(1) NOT NULL DEFAULT '1',
`created_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `email` (`email`)
) ENGINE=MyISAM AUTO_INCREMENT=17 DEFAULT CHARSET=latin1;
I need a performant query giving me the ranking of each user ranked on how many likes they got on all their items?
I managed to write this:
SELECT #rank := #rank + 1 AS rank, m.*
FROM (SELECT
users.first_name as first_name,
users.last_name as last_name,
count(upvotes.item_id) as total
FROM upvotes
INNER JOIN users
ON users.id = (SELECT items.user_id FROM items WHERE items.id = upvotes.item_id LIMIT 1)
GROUP BY users.id
ORDER BY total DESC
) m, (SELECT #rank := 0) r
But I reckon this will be super slow when the database grows...
You can do a simple join query in order to get the total likes for each item of user and order your results with the resulting count in descending order
SELECT u.*,i.*,COUNT(DISTINCT up.user) `total_user_likes_item`
FROM users u
JOIN items i ON(i.user_id = u.id)
JOIN upvotes up ON(up.item_id = i.id)
GROUP BY u.id,i.id
ORDER BY u.id,i.id,total_user_likes_item DESC
Edit from comments For user total likes you remove i.id from group by as below query
SELECT u.*,COUNT(DISTINCT up.user) `total_user_likes_item`
FROM users u
JOIN items i ON(i.user_id = u.id)
JOIN upvotes up ON(up.item_id = i.id)
GROUP BY u.id
ORDER BY total_user_likes_item DESC
I'll try answer your question:
In table users you can add row sum_upvotes. Every time when someone get one like (vote) you will increment this column by:
UPDATE users
SET sum_upvotes = sum_upvotes + 1
;
Of course, you will insert a column in table upvotes.
Finally, you query to select users and order them by upvotes will look like this
SELECT first_name, last_name
FROM users
ORDER BY sum_upvotes
;
Hope this helps.

Correct mysql query to query one table and have that provide information for another table query

I have 2 separate tables, both of which I need to query simultaneously to get the correct information to display. The tables are members and posts. Through an html form, a user enters criteria for the members table, and then I need to use the primary index of all those specific members to find all the posts submitted by those members and then do a sort on the posts table results. The results will be a mixture of rows from the two tables. Both tables have a primary index of the name 'id'. So far what I've come up with is:
$sql_get_posts = mysqli_query($link, "(SELECT id, username FROM members WHERE active='y' AND gender='M' AND city='Yuma' AND state='Arizona') UNION (SELECT * FROM posts WHERE member_id='id' AND active='y' ORDER BY list_weight DESC)") or die(mysqli_error($link));
The error I'm getting is "The used SELECT statements have a different number of columns".
I need to then cycle through the returned results from both tables to populate the content seen by the user:
<?php
while ($row = mysqli_fetch_array($sql_get_posts)) {
$post_id = $row['id']; //This should be the post primary index named 'id', not the member primary index also name 'id'
$member_id = $row['member_id']; //This is the member_id row in the post table referencing this particular member who wrote this post
$member_username = $row['username']; //This is a row stored in the member table
$title = $row['title']; //This is a row stored in post table
******//and on and on getting rows from only the post table
}
Edit My SQL tables:
CREATE TABLE IF NOT EXISTS `members` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(20) NOT NULL,
`age` varchar(3) NOT NULL,
`gender` varchar(1) NOT NULL,
`city` varchar(20) NOT NULL,
`state` varchar(50) NOT NULL,
`active` enum('y','n') NOT NULL DEFAULT 'y',
`created_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;
CREATE TABLE IF NOT EXISTS `posts` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`member_id` int(11) NOT NULL,
`title` text NOT NULL,
`comments` enum('y','n') NOT NULL DEFAULT 'y',
`post_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`list_weight` double NOT NULL,
`active` enum('y','n') NOT NULL DEFAULT 'y',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=47 ;
Use join instead of union, union assumes the tables you're combining are similar, whereas join merges the columns of two tables.
Something like:
SELECT members.id, members.username, posts.*
FROM members
INNER JOIN posts
ON members.id = posts.member_id
WHERE members.active='y' AND members.gender='M' AND members.city='Yuma' AND members.state='Arizona'
ORDER BY posts.list_weight DESC
SELECT statement within the UNION must have the same number of columns. The columns must also have similar data types. Also, the columns in each SELECT statement must be in the same order.
But you have selected only 2 columns in first query and "*" for second select query
use joins
SELECT m.id, m.username,p.* FROM members m JOIN posts p on m.active='y' AND m.gender='M' AND m.city='Yuma' AND m.state='Arizona' and p.member_id='id' AND p.active='y' ORDER BY p.list_weight DESC
or you can use
SELECT m.id, m.username,p.* FROM members m,posts p where m.active='y' AND m.gender='M' AND m.city='Yuma' AND m.state='Arizona' and p.member_id='id' AND p.active='y' ORDER BY p.list_weight DESC

select 3 items with higher sales

I am wanting to select the 3 biggest selling records with this is my table
CREATE TABLE IF NOT EXISTS `contas` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_service` int(11) DEFAULT NULL,
`data` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=28 ;
the 'id_service' is the main column, the more sales, more records are added with the same 'id_service'.
so how do I do this without using PHP and select in descending order?
I tried this
select id_service, count(*) as id_service
from vendas WHERE id_service is not null
group by id_service order by id_service desc LIMIT 3
You have aliased both columns to the same name. No wonder the query is confused. Try this:
select id_service, count(*) as cnt
from vendas WHERE id_service is not null
group by id_service
order by cnt desc
LIMIT 3;

MySQL "NOT IN" Query Optimization

Optimizng MySQL queries isn't my expertise, so I was wondering if someone could help me formulate the most optimal query here (and indices).
As background, I'm trying to find a distinct visitor id within a table of transactions with certain where criteria (date range, not a certain product, etc. as you see in the query below). Transactions and visitors have a one to many relationship, so there can be many transactions to a single visitor.
Another requirement for the results is that if a visitor_id is found in the result, it must be the first instance of a visitor_id (by date_time) in the entire table. In other words, the visitor_id should only exist in the date range set in the primary query and at no time beforehand.
Here's what I've put together so far. It uses NOT IN and a subquery, but this doesn't seem ideal because the query takes between 2-3 seconds being that the table has over 500k records. I've tried a few variations of indices, but nothing seems to really work.
Here's the query.
SELECT DISTINCT visitor_id, date_time
FROM pt_transactions
WHERE visitor_id NOT IN (SELECT visitor_id FROM pt_transactions WHERE date_time < '$this->_date_time_start')
AND campaign_id = $this->_campaign_id
AND a_aid = '$a_aid'
AND date_time >= '$this->_date_time_start'
AND date_time <= '$this->_date_time_end'
AND product_id != 65
And here's the complete table structure.
CREATE TABLE IF NOT EXISTS `pt_transactions` (
`id` int(32) NOT NULL AUTO_INCREMENT,
`type` varchar(2) NOT NULL COMMENT 'New Lead (NL), Raw Optin (RO), Base Sale (BS), Upsell Sale (US), Recurring Sale (RS), Base Refund (BR), Upsell Refund (UR), Recurring Refund (RR), Unknown Refund (XR), or Chargeback (C)',
`date_time` datetime NOT NULL,
`amount` varchar(255) NOT NULL,
`a_aid` varchar(255) NOT NULL,
`subid1` varchar(255) NOT NULL,
`subid2` varchar(255) NOT NULL,
`subid3` varchar(255) NOT NULL,
`product_id` int(16) NOT NULL,
`visitor_id` int(32) NOT NULL,
`campaign_id` int(16) NOT NULL,
`last_click_id` int(16) NOT NULL,
`trackback_type` varchar(255) NOT NULL COMMENT 'Shows if the transaction is tracked back to the original visitor via cookie or via IP. Usually only applies to sales via pixel.',
`original_transaction_id` int(32) NOT NULL COMMENT 'Reference to original transaction id, in this table, if type is RS, R, or C',
`recurring_transaction_id` varchar(32) NOT NULL COMMENT 'Reference to existing RecurringTransaction if type is RS',
PRIMARY KEY (`id`),
KEY `visitor_id` (`visitor_id`),
KEY `campaign_id` (`visitor_id`,`campaign_id`,`amount`,`product_id`),
KEY `transaction_retrieval_group` (`campaign_id`,`date_time`,`a_aid`),
KEY `type` (`type`),
KEY `date_time` (`date_time`),
KEY `original_source` (`campaign_id`,`a_aid`,`date_time`,`product_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=574636
You can try NOT EXISTS
SELECT DISTINCT visitor_id, date_time
FROM pt_transactions t
WHERE campaign_id = $this->_campaign_id
AND a_aid = '$a_aid'
AND date_time >= '$this->_date_time_start'
AND date_time <= '$this->_date_time_end'
AND product_id != 65
AND NOT EXISTS
(
SELECT *
FROM pt_transactions
WHERE visitor_id = t.visitor_id
AND date_time < '$this->_date_time_start'
)
Do EXPLAIN <query> and see how your indices are used. If you want you can post results in your question in a textual form.
From your query what i can understand is that...
Their is no need to write NOT IN Statement...
Because, you are already keeping a check for
date_time >= '$this->_date_time_start'
so thier is no need to check date_time < '$this->_date_time_start' in not NOT IN statement.
Only below should work fine :)
SELECT DISTINCT visitor_id, date_time
FROM pt_transactions
WHERE
AND campaign_id = $this->_campaign_id
AND a_aid = '$a_aid'
AND date_time >= '$this->_date_time_start'
AND date_time <= '$this->_date_time_end'
AND product_id != 65

How do I query the latest save progress of a list of users. (php/html)

I have a register and login site where people can click save progress on a form and it inserts a new row with their session id in column 2 as (user_id).
I also have an admin login where I can see their entries but it shows a list all their saves.
I wonder if you could help me figure out a query to list all the latest save progresses of each unique person? like (id,user_id,name,score): (3,3,bob, score 5) (6,4,sam, score 30) without showing all saves of a user's past saves like:
(1,3,bob, score 5) (2,4,sam, score 30) (3,3,bob, score 5) (4,4,sam, score 30)
I need the latest save of each user.
Like the latest id of a distinct list of user_id. Hope this makes sense. Thanks!
select user_id,name,score from your_table where (user_id,id) in (select user_id,max(id) from your_table group by user_id)
Considering the below formats for your tables
CREATE TABLE IF NOT EXISTS `user` (`user_id` int(11) NOT NULL auto_increment,
`user_name` varchar(200) collate latin1_general_ci NOT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci AUTO_INCREMENT=1;
CREATE TABLE IF NOT EXISTS `user_score` (
`id` int(11) NOT NULL auto_increment,
`user_id` int(11) NOT NULL,
`user_score` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci AUTO_INCREMENT=1;
Please try executing the below sql select query for retrieving latest score for each user
SELECT u . * ,s.user_score,s.id FROM user u JOIN user_score s ON u.user_id = s.user_id WHERE id IN (SELECT MAX( id ) FROM user_score GROUP BY user_id)

Categories