Combine two mySQL sum queries into one which use different where clauses - php

I have two sum quires referencing different tables in mySQL. How can I combine the two in order to calculate the difference between the two values for each user in the database?
Query 1:
SELECT tbl_users.name, tbl_holiday_allocation.`year`,
tbl_holiday_allocation.allocation,
tbl_holiday_allocation.carried_forward,
tbl_holiday_allocation.lieu_days,
SUM(tbl_holiday_allocation.allocation+tbl_holiday_allocation.carried_forward+tbl_holiday_allocation.lieu_days) AS TotalAllocation
FROM tbl_holiday_allocation
RIGHT JOIN tbl_users ON tbl_users.username = tbl_holiday_allocation.username
WHERE year = 2014 AND user_active = 1
AND (jobtitle like '".$search_string3."' OR department like '".$search_string3."')
GROUP BY tbl_users.name
ORDER BY tbl_users.id ASC
Query 2
SELECT tbl_users.name, Sum(tbl_holidays.NumberOfDays) AS ApprovedTotal
FROM tbl_users
LEFT JOIN tbl_holidays ON tbl_users.username = tbl_holidays.username
WHERE ((NumberOfDays < 6 AND LMStatus = 1 AND (department = 'Qual' or department = 'Quant' or department = 'Qual/Quant') AND RequestType = 'Holiday')
OR (NumberOfDays < 10 AND LMStatus = 1 AND (department = 'Accounts' or department = 'HR' or department = 'IT' or department = 'Support' or department = 'Operations') AND RequestType = 'Holiday')
OR (NumberOfDays > 5 AND NumberOfDays < 10 AND LMStatus = 1 AND HOStatus = 1 AND (department = 'Qual' or department = 'Quant' or department = 'Qual/Quant') AND RequestType = 'Holiday')
OR (NumberOfDays > 9 AND 'LMStatus' = 1 AND HOStatus = 1 AND CEOStatus = 1 AND (department = 'Qual' or department = 'Quant' or department = 'Qual/Quant') AND RequestType = 'Holiday')
OR (NumberOfDays > 9 AND LMStatus = 1 AND HOStatus = 1 AND CEOStatus = 1 AND (department = 'Qual' or department = 'Quant' or department = 'Qual/Quant') AND RequestType = 'Holiday') OR (NumberOfDays > 9 AND LMStatus = 1 AND CEOStatus = 1 AND (department = 'Accounts' or department = 'Support' or department = 'HR' or department = 'IT' or department = 'Operations') AND RequestType = 'Holiday'))
AND user_active = 1
AND (jobtitle like '".$search_string3."' OR department like '".$search_string3."')
GROUP BY tbl_users.name
ORDER BY tbl_users.id ASC
In the end I'd like to be able to take SUM TotalAllocation - SUM ApprovedTotal
User Table:
CREATE TABLE `tbl_users` (
`id` tinyint(3) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
KEY `1` (`username`)
) ENGINE=MyISAM AUTO_INCREMENT=144 DEFAULT CHARSET=utf8
Holiday Allocation Table:
CREATE TABLE `tbl_holiday_allocation` (
`id` int(3) NOT NULL AUTO_INCREMENT,
`username` varchar(255) DEFAULT NULL,
`year` varchar(4) DEFAULT NULL,
`allocation` int(3) DEFAULT NULL,
`carried_forward` int(3) DEFAULT '0',
`lieu_days` decimal(3,1) DEFAULT '0.0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=93 DEFAULT CHARSET=latin1
Holiday Table
CREATE TABLE `tbl_holidays` (
`id` int(6) NOT NULL AUTO_INCREMENT,
`username` varchar(255) CHARACTER SET latin1 DEFAULT NULL,
`StartDate` varchar(255) DEFAULT NULL,
`EndDate` varchar(255) DEFAULT NULL,
`RequestType` varchar(255) DEFAULT NULL,
`WhichHalf` varchar(3) DEFAULT '0',
`Details` varchar(255) DEFAULT NULL,
`UserStatus` int(1) DEFAULT '0',
`LMStatus` int(1) DEFAULT '0',
`HOStatus` int(1) DEFAULT '0',
`CEOStatus` int(1) DEFAULT '0',
`HRStatus` int(1) DEFAULT '0',
`NumberOfDays` decimal(3,1) DEFAULT NULL,
`user_comments` varchar(255) DEFAULT NULL,
`LMDeclineComment` varchar(255) DEFAULT NULL,
`HODeclineComment` varchar(255) DEFAULT NULL,
`CEODeclineComment` varchar(255) DEFAULT NULL,
`HRDeclineComment` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=579 DEFAULT CHARSET=utf8

SELECT q1..name, q1.`year`,
q1.allocation, q1.carried_forward,
q1.lieu_days, q1.TotalAllocation,
q2.ApprovedTotal
FROM (
~~INSERT Query1 here ~~
) AS q1
INNER JOIN
(
~~INSERT Query2 here ~~
) as q2
ON q1.username=q2.username;

$sql="select SUM(HA.allocation+HA.carried_forward+HA.lieu_days) AS TotalAllocation,Sum(H.NumberOfDays) AS ApprovedTotal where tbl_holiday_allocation as HA,tbl_holidays as H where your condition";
Hope this will be what you want.
Have a look in JOIN syntax

Related

Reduce MySQL request time with Codeigniter

I use Codeigniter 3.1.11 and have some code which makes one big query to MySQL with an array. The time of a query with a limit of 30000 is about 9 seconds.
How can I reduce the request time? Maybe by using some indexes on my table, or do you know another method? If I need to use indexes, what indexes would I need to use and how can I use these indexes in my query on Codeigniter?
Code from model:
function rows_update() {
$query = $this->db->order_by('rating', 'DESC')->get_where('members', 'game_rating_and_balance_update_last_time <= now() - INTERVAL 1 DAY', '30000', '0');
$arrUpdateBatchData = [];
while ($row = $query->unbuffered_row('array'))
{
// some code here
$arrUpdateData = [
'UserID' => $row['UserID'],
'game_vault_balance' => $new_game_vault_balance,
'game_available_balance' => $new_game_available_balance,
'rating' => $rating_member,
'game_rating_and_balance_update_last_time' => date('Y-m-d H:i:s')
];
$arrUpdateBatchData[] = $arrUpdateData;
if (count($arrUpdateBatchData) > 500)
{
$this->db->update_batch('members', $arrUpdateBatchData, 'UserID');
$arrUpdateBatchData = [];
}
}
//update last items
if (count($arrUpdateBatchData) > 0)
{
$this->db->update_batch('members', $arrUpdateBatchData, 'UserID');
$arrUpdateBatchData = [];
}
return;
}
Raw query to MySQL with update_batch (I simply write only one row from an array):
UPDATE members SET game_vault_balance = CASE WHEN UserID = '9915075' THEN 803.60516004772 ELSE game_vault_balance END, game_available_balance = CASE WHEN UserID = '9915075' THEN 4.1253850908788 ELSE game_available_balance END, rating = CASE WHEN UserID = '9915075' THEN 0.24 ELSE rating END, game_rating_and_balance_update_last_time = CASE WHEN UserID = '9915075' THEN '2020-07-24 22:00:36' ELSE game_rating_and_balance_update_last_time END WHERE UserID IN('9915075')
Table structure:
CREATE TABLE `members` (
`id` int(10) UNSIGNED NOT NULL,
`UserID` varchar(64) NOT NULL,
`telegram_id` varchar(64) DEFAULT NULL,
`first_name` varchar(64) DEFAULT NULL,
`last_name` varchar(64) DEFAULT NULL,
`language` varchar(64) DEFAULT NULL,
`currency` varchar(64) DEFAULT NULL,
`status` varchar(64) DEFAULT NULL,
`rating` varchar(64) DEFAULT NULL,
`game_vault_balance` decimal(32,8) DEFAULT 0.00000000,
`game_available_balance` decimal(32,8) DEFAULT 0.00000000,
`game_rating_and_balance_update_last_time` datetime DEFAULT NULL,
`updated` datetime DEFAULT NULL,
`created` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Indexes of this table:
ALTER TABLE `members`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `UserID` (`UserID`) USING BTREE;
AUTO_INCREMENT for the members table:
ALTER TABLE `members`
MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT;
COMMIT;

PHP If else and some logics

I just having some problem of if/else or somewhat logical things in here, I have a fullcalendar that shows all the date that being reserve, I limit the reserve by 5 per date, but when I having a 2 or more reserved on the date and having reserve by other date, It gives me the same result as 4.
global $db;
$data = array();
$query = "SELECT * FROM reserve_master
INNER JOIN reserve_details
on reserve_master.reserve_id = reserve_details.reserve_id
INNER JOIN reserve_indicator
on reserve_master.reserve_id = reserve_indicator.reserve_id
WHERE reserve_indicator.touserid = '$id'
AND reserve_master.type = 'Repair' ";
$res = mysqli_query($db,$query);
$count = mysqli_num_rows($res);
$count = 5 - $count;//count the available slot
$date_changed = "";
$reserve_id = 0;
foreach ($res as $row)
{
date_default_timezone_set('Asia/Manila');
$current_timestamp = strtotime($row["dateend"] . '+1 day');
$time = date("Y/m/d",$current_timestamp);
if($row["datestart"] == $date_changed)
{
//This is for avoiding repeating graph on fullcalendar
}
else
{
if(empty($count))
{
$count = '0';
}
else
{
$count;
}
$data[] = array(
'id' => $row["reserve_id"],
'title' => $count,
'start' => $row["datestart"],
'end' => $time,
'color' =>getColor($row["status"])
);
$date_changed = $row["datestart"];
$reserve_id = $row["reserve_id"];
}
}
echo json_encode($data);
This is image of the error with captions
Database
CREATE TABLE `reserve_master` (
`reserve_id` int(11) NOT NULL AUTO_INCREMENT,
`datestart` date NOT NULL,
`dateend` date NOT NULL,
`type` varchar(255) NOT NULL,
PRIMARY KEY (`reserve_id`)
) ENGINE=InnoDB AUTO_INCREMENT=47 DEFAULT CHARSET=latin
CREATE TABLE `reserve_indicator` (
`indicator_id` int(11) NOT NULL AUTO_INCREMENT,
`reserve_id` int(11) NOT NULL,
`touserid` int(11) NOT NULL,
`byuserid` int(11) NOT NULL,
PRIMARY KEY (`indicator_id`),
KEY `reserve_id` (`reserve_id`) USING BTREE,
CONSTRAINT `reserve_indicator_ibfk_1` FOREIGN KEY (`reserve_id`) REFERENCES `reserve_master` (`reserve_id`)
) ENGINE=InnoDB AUTO_INCREMENT=35 DEFAULT CHARSET=latin1
CREATE TABLE `reserve_details` (
`details_id` int(11) NOT NULL AUTO_INCREMENT,
`reserve_id` int(11) NOT NULL,
`title` varchar(255) NOT NULL,
`description` varchar(255) NOT NULL,
`status` varchar(255) NOT NULL,
`location` varchar(255) NOT NULL,
PRIMARY KEY (`details_id`),
KEY `reserve_id` (`reserve_id`) USING BTREE,
CONSTRAINT `reserve_details_ibfk_1` FOREIGN KEY (`reserve_id`) REFERENCES `reserve_master` (`reserve_id`)
) ENGINE=InnoDB AUTO_INCREMENT=35 DEFAULT CHARSET=latin1
All i had tried is to get the right available on the 2nd of febuary 2018 and not the others.
The code is mess, I'm very sorry;
Problem is solved already;
I use eventLimit on fullcalendar and set it to 1
Count = 5 not subtracted by the num_rows
and few set on if-statement
Few answer I used rows and res as it is easy to indicate for results and rows, and i used it same as other queries.
Thank you.

Select two columns from two tables and order by their values DESC

With this code I'm getting news from the database and order it by column "views":
<?php
$getnewsinfo = mysql_query("SELECT * FROM news ORDER BY views DESC LIMIT 5");
while($newsinforow = mysql_fetch_array($getnewsinfo))
{
$newsid = $newsinforow['id'];
$title = $newsinforow['title'];
$author = $newsinforow['author'];
$date = date('d.m.Y', $newsinforow['date']);
$picture = $newsinforow['picture'];
$picture_desc = $newsinforow['picture_desc'];
$category = $newsinforow['category'];
$text = $newsinforow['text'];
?>
Now I want to order the news by views and by the number of comments, but I have no idea how.
Here is my database structure :
CREATE TABLE IF NOT EXISTS `news` (
`id` int(11) NOT NULL auto_increment,
`views` int(11) NOT NULL default '0',
`title` varchar(255) NOT NULL,
`author` varchar(255) NOT NULL,
`date` varchar(255) NOT NULL,
`picture` varchar(255) NOT NULL,
`picture_desc` varchar(255) NOT NULL,
`category` varchar(255) NOT NULL,
`text` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=6 ;
CREATE TABLE IF NOT EXISTS `news_comments` (
`id` int(11) NOT NULL auto_increment,
`news_id` int(11) NOT NULL,
`name` varchar(255) NOT NULL,
`email` varchar(255) NOT NULL,
`website` varchar(255) NOT NULL,
`text` text NOT NULL,
`date` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=16 ;
I also want to ask you... do you have any comments on the code and database structure ?
Try this sql
SELECT n.*,count(nc.id) as cnt FROM news as n, news_comments as nc where n.id = nc.news_id group by nc.news_id ORDER BY views DESC,cnt DESC LIMIT 5

PHP/MYSQL - Which Join Statement To Use To Simplify My Queries?

I have these 2 queries and i would like to join them into one but i am unsure of how to go about it.
Query 1:
$query = "SELECT * FROM ".$db_tbl_comics." WHERE ".$db_fld_comics_publisher."='".$pub_id."'
AND ".$db_fld_comics_active."='1' GROUP BY ".$db_fld_comics_arc;
Query 2:
$q2 = mysql_query('SELECT '.$db_fld_arcs_title.' FROM '.$db_tbl_arcs.'
WHERE '.$db_fld_arcs_id.'="'.$result[$db_fld_comics_arc].'"');
Comics Table:
CREATE TABLE IF NOT EXISTS `comics` (
`id` varchar(255) NOT NULL,
`arc` int(255) NOT NULL,
`title` varchar(255) NOT NULL,
`issue` decimal(5,1) DEFAULT NULL,
`price` decimal(10,2) NOT NULL,
`plot` longtext NOT NULL,
`publisher` int(255) NOT NULL,
`isbn` varchar(255) NOT NULL,
`published` date NOT NULL,
`cover` varchar(255) NOT NULL DEFAULT './images/nopic.jpg',
`added` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`views` int(255) NOT NULL DEFAULT '0',
`active` int(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `arc` (`arc`,`title`,`issue`,`publisher`)
);
Arcs Table:
CREATE TABLE IF NOT EXISTS `arcs` (
`id` int(255) NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
`plot` longtext NOT NULL,
`added` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `title` (`title`)
);
What I need to do is get the Arcs Title from the arcs table for the respective comic arc.
You need to use INNER JOIN for that since I presume that records are present on both tables.
SELECT a.*, b.title
FROM comics a INNER JOIN arcs b
on a.id = b.id
WHERE a.Title = 'VALUEHERE'
displays all details from comics table and the title of the arc
as simple as (joining 2 queries in one, by selecting only the required field and using IN):
SELECT
'.$db_fld_arcs_title.'
FROM '.$db_tbl_arcs.'
WHERE '.$db_fld_arcs_id.' IN (
SELECT '.$db_fld_comics_arc.'
FROM '.$db_tbl_comics.'
WHERE '.$db_fld_comics_publisher.'='".$pub_id."'
AND '.$db_fld_comics_active.'='1' GROUP BY '.$db_fld_comics_arc.'
)

How do I select and match from multiple tables?

This is my table layout:
-- Table structure for table `areas`
CREATE TABLE IF NOT EXISTS `areas` (
`ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) unsigned NOT NULL,
`country` varchar(20) NOT NULL,
`city` varchar(20) NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
-- Table structure for table `matches`
CREATE TABLE IF NOT EXISTS `matches` (
`ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) unsigned NOT NULL,
`view_id` bigint(20) unsigned NOT NULL,
`status` enum('h','n') NOT NULL,
`exp_date` date NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
-- Table structure for table `users`
CREATE TABLE IF NOT EXISTS `users` (
`ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`limit_age` varchar(5) NOT NULL DEFAULT '18:30',
`limit_gender` varchar(2) DEFAULT NULL,
`notifications` int(11) NOT NULL DEFAULT '0',
`name` varchar(30) NOT NULL,
`email` varchar(40) NOT NULL,
`image_big` varchar(120) NOT NULL,
`image_small` varchar(120) NOT NULL,
`crop_data` int(11) DEFAULT NULL,
`visible` tinyint(1) NOT NULL DEFAULT '0',
`age` int(11) DEFAULT NULL,
`registered_at` datetime NOT NULL,
`views` bigint(20) unsigned NOT NULL DEFAULT '0',
`hots` bigint(20) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`ID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=15 ;
I will try to explain this better:
I have a given ID.
I would like to select one entry from users which is not the ID i have given
AND which user_id does not exist in matches
AND has visible = 1
AND where any country + city matches the given users country + city
Is this the correct way to do it (12 is an example of an given ID):
SELECT *
FROM users a
INNER JOIN areas ON areas.user_id = a.id
WHERE a.id NOT IN (SELECT user_id FROM matches)
AND NOT a.id = '12'
AND a.limit_age = '18:30'
AND a.visible = '1'
AND areas.country = 'sverige'
AND areas.city = 'gbg'
Sorry for the confusion :)
Ok, I'll make an attempt at this:
SELECT *
FROM users a
INNER JOIN areas ON areas.user_id = a.id
WHERE a.id NOT IN (SELECT user_id FROM matches)
AND a.visible = '1'
AND a.limit_age = '18:30'
AND a.limit_gender = 'f'
AND areas.country = ?
AND areas.city = ?;
This is SELECTing from "users", and returning a result only if that user also has an entry in the "areas" table. The first item in the WHERE clause ensures that a row will not be returned if the users.id (a.id) is found in the user_id field on the "matches" table. Next, I added checks for visible = 1, limit_age, and limit_gender as specified in his attempt. Finally, I left country and city parameterized so that they can be added as parameters in the php code. If anything that should give you a starting point.

Categories