PHP / MySQL query - php

After days of failing I hope that someone more skilled can help me with a solution.
I have two tables, one containing stocks and the other stock values. Please, you do not have to comment on field types etc as this is not a production development, I am only trying to get a grasp on join and mysql alias.
-- Stocks table:
DROP TABLE IF EXISTS `stocks`;
CREATE TABLE `stocks` (
`stock_id` int(11) NOT NULL AUTO_INCREMENT,
`stock_name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`stock_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
-- Sample records:
INSERT INTO `stocks` VALUES ('1', 'HighTech');
INSERT INTO `stocks` VALUES ('2', 'NanoTech');
INSERT INTO `stocks` VALUES ('3', 'DotCom');
INSERT INTO `stocks` VALUES ('4', 'NewBiz');
-- Values table:
DROP TABLE IF EXISTS `vals`;
CREATE TABLE `values` (
`vals_id` int(11) NOT NULL AUTO_INCREMENT,
`stock_id` varchar(255) DEFAULT NULL,
`stock_value` int(11) DEFAULT NULL,
PRIMARY KEY (`vals_id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
-- Sample records:
INSERT INTO `vals` VALUES ('1', '1', '50');
INSERT INTO `vals` VALUES ('2', '1', '700');
INSERT INTO `vals` VALUES ('3', '1', '540');
INSERT INTO `vals` VALUES ('4', '3', '15');
INSERT INTO `vals` VALUES ('5', '3', '44');
INSERT INTO `vals` VALUES ('6', '1', '60');
INSERT INTO `vals` VALUES ('7', '2', '10');
INSERT INTO `vals` VALUES ('8', '3', '53');
There could be 100s of stocks and 1000s of value records.
What I want to do is to print each stock together with a single (latest) stock value.
For stock number 3 I want to echo "DotCom" and the latest value "53", none of the others values.

Oh yeah , your table name values creating problem here , try to change it to someother name like vals or something.it would works/
here it is
SELECT * FROM stocks S JOIN vals V ON V.vals_id = ( SELECT MAX(vals_id) FROM vals Va WHERE Va.stock_id = S.stock_id )

Related

Select random item from table with ratio

I'm trying to create an mysql table with some data in it which are special items. For example we have item1(chanse: 1), item2(chanse: 1), item(chance: 20%) and
item3 (chance: 20) etc.. etc...
- Chances are in %
So I created a table with the following information:
CREATE TABLE `special_items` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`item_id` int(11) NOT NULL,
`item_name` varchar(255) DEFAULT NULL,
`item_type` enum('SPECIAL','SILVER','BRONZE','GOLD') NOT NULL DEFAULT 'BRONZE',
`item_ratio` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`) USING BTREE,
UNIQUE KEY `item` (`item_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of special_items
-- ----------------------------
INSERT INTO `special_items` VALUES ('1', '200', 'special_name1', 'BRONZE', '80');
INSERT INTO `special_items` VALUES ('2', '204', 'special_name2', 'BRONZE', '4');
INSERT INTO `special_items` VALUES ('3', '875', 'special_name3', 'BRONZE', '80');
INSERT INTO `special_items` VALUES ('4', '900', 'special_name4', 'BRONZE', '60');
INSERT INTO `special_items` VALUES ('5', '901', 'special_name5', 'SILVER', '90');
INSERT INTO `special_items` VALUES ('6', '968', 'special_name6', 'BRONZE', '65');
INSERT INTO `special_items` VALUES ('7', '777', 'special_name7', 'BRONZE', '30');
What we want to do now is select from 800 rows 5 random items by there ratio. So it needs to have the following requirements:
Always random rows.
Select rows by there ratio (chance in the table is percentage for example)
I also found this query which almost fits the solution but its don't know how I would do this for the random ratio (percentage)
SELECT item_name
FROM special_items AS r1 JOIN
(SELECT CEIL(RAND() *
(SELECT MAX(id)
FROM special_items)) AS id)
AS r2
WHERE r1.id >= r2.id
ORDER BY r1.id ASC
LIMIT 5
If this can be done through PHP it would be awesome.
I'm open to any and all suggestions. I'll also be trying to figure this out on my own in the meantime, but I'm still stuck.
Let me guess that by "chanse" [sic], you mean that each row has a weight, and you want this weight to contribute to the chance of a row being selected.
One method is to generate a random number for each row, multiply by the weight, and then return 5 rows with the highest generated number. It is unclear what you mean by the chance, so this might do what you want:
select si.*
from (select si.*, rand() * item_ratio as weight
from special_items si
) si
order by weight desc
limit 5;
Note: The subquery is needed so the weight is only calculated once per line. I think this does the same thing:
select si.*, rand() * item_ratio as weight
from special_items si
order by weight desc
limit 5;
But MySQL can be peculiar.

Proper solution for storing only few values - column or table?

I've got a huge table 'books' storing book information where I plan to have a row for media type, let's call it 'media_ID'. I know that I'm dealing here with only three possible values: book, ebook and audiobook.
So, making a separate table out of this three values seems to me like wasting especially when I have to include it in every query which feels also unnecessary to me. So what's a clean solution for such cases? Maybe using a PHP array in a config file? What are you using?
books
-------
ID
media_ID
title
...
medias
-------
ID
type
MySQL data:
CREATE `books` (
`ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`media_ID` tinyint(4) NOT NULL DEFAULT '1',
`title` tinytext NOT NULL,
)
INSERT INTO `books` (`ID`, `media_ID`, `title`) VALUES
(1, 1, 'Some print book title'),
(2, 1, 'Other print book title'),
(3, 2, 'First ebook title'),
(4, 2, 'Second ebook title'),
(5, 3, 'Single audio book title');
CREATE TABLE `medias` (
`ID` tinyint(4) NOT NULL AUTO_INCREMENT,
`type` tinytext NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;
INSERT INTO `medias` (`ID`, `Medium`) VALUES
(1, 'book'),
(2, 'ebook'),
(3, 'audiobook');
Or just php array:
$medias = array("book", "ebook", "audiobook");
Using a separate table for just 3 values is NOT out of the ordinary.
Furthermore this will give you the option of adding more attributes in the future-if the need arises...something that will be an issue with ENUM column type.
In my app...I have such a table that stores the payments packages the user selected...and these are only three.
So go for a table if you are not sure about your future needs/requirements.
Personally I'd use a enum for this.
`mediaType` ENUM('book', 'ebook', 'audiobook') not null
It's also possible to use lookup tables to handle enumaration. Just found the solution here: How to handle enumerations without enum fields in a database.
CREATE `books` (
`ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`media` tinyint(4) NOT NULL DEFAULT '1',
`title` tinytext NOT NULL,
FOREIGN KEY (media) REFERENCES medias(Medium)
)

checkbox check with database data

i have two mysql tables and looks like as follows. iam using PHP and MySQL
CREATE TABLE IF NOT EXISTS `subject_category` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`sid` int(5) DEFAULT NULL,
`category` varchar(50) DEFAULT NULL,
`subject` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=191 ;
INSERT INTO `subject_category` (`id`, `sid`, `category`, `subject`) VALUES
(1, 1, 'GCE O/L', 'Sinhala'),
(2, 2, 'GCE O/L', 'Development Studies'),
(3, 3, 'GCE O/L', 'History'),
(4, 4, 'GCE O/L', 'Mathematics'),
(5, 5, 'GCE O/L', 'Citizan Education'),
and
CREATE TABLE IF NOT EXISTS `user_subjects` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`uid` bigint(20) NOT NULL,
`usid` int(4) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=43 ;
INSERT INTO `user_subjects` (`id`, `uid`, `usid`) VALUES
(11, 142247454430186, 1),
(12, 142247454430186, 3),
(13, 142247454430186, 5)
actually what i need is, need to create check-box array using first table data. this part is already done. then i need to checked checkbox match with second table (subject_category.id=user_subjects.usid) for the particular user_subject.uid
FINALLY i need 5 check boxes for data in first table and 3 of them have selected with to second table values
please help me to solve this problem
I think you start off the wrong way, you should do it in 1 step, not in two steps.
The mysql query you need is:
$query = 'SELECT sc.subject, CASE WHEN us.id IS NULL THEN "" ELSE "checked" AS checked
FROM subject_category sc
LEFT JOIN user_subjects us ON (us.usid = sc.id)';
With the result of this query you should be able to generate the checked and unchecked checkboxes at once.
NOTE: I don't know which columns you need and if you needed sc.id or sc.sid in the join, but I think you can create the right query with this example.
Next step PHP (with mysql_* function as the TS asks in comment, I know you should use PDO or mysqli):
$result = mysql_query($query);
while ($line = mysql_fetch_assoc($result)){
echo '<input type="checkbox" checked="'.$line['checked'].'" name="subject" value="'. $line['subject'] .'" /> '.$line['subject'];
}

Properly done join 4 tables with using group by

I am new in using advanced SQL queries and I am struggling with one query.
I have booking system created in php and it is using 4 tables:
site_days
site_timeslots
site_bookings
site_teams
each site_team is related to site_booking
each site_booking is related to site_timeslot
each site_timeslot is related to site_days
there can be more site_timeslots related to one site_day
there can be more site_bookings related to one site_timeslot
there can be more site_teams related to one site_bookings
you can create test tables with this sql:
-- Adminer 3.6.3 MySQL dump
SET NAMES utf8;
SET foreign_key_checks = 0;
SET time_zone = 'SYSTEM';
SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO';
DROP TABLE IF EXISTS `site_bookings`;
CREATE TABLE `site_bookings` (
`id` int(11) NOT NULL auto_increment,
`timeslot_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
INSERT INTO `site_bookings` (`id`, `timeslot_id`) VALUES
(1, 6443);
DROP TABLE IF EXISTS `site_days`;
CREATE TABLE `site_days` (
`id` int(11) NOT NULL auto_increment,
`date` date NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=93 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
INSERT INTO `site_days` (`id`, `date`) VALUES
(85, '2013-04-01'),
(92, '2013-04-02');
DROP TABLE IF EXISTS `site_teams`;
CREATE TABLE `site_teams` (
`id` int(11) NOT NULL auto_increment,
`booking_id` int(11) NOT NULL,
`name` varchar(100) collate utf8_bin NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
INSERT INTO `site_teams` (`id`, `booking_id`, `name`) VALUES
(1, 1, 'Avengers'),
(2, 1, 'Big Five');
DROP TABLE IF EXISTS `site_timeslots`;
CREATE TABLE `site_timeslots` (
`id` int(11) NOT NULL auto_increment,
`day_id` int(11) NOT NULL,
`date` date NOT NULL,
`starts` time NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7152 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
INSERT INTO `site_timeslots` (`id`, `day_id`, `date`, `starts`) VALUES
(6443, 85, '2013-04-01', '08:00:00'),
(6444, 85, '2013-04-01', '08:10:00'),
(7098, 92, '2013-04-02', '08:00:00'),
(7099, 92, '2013-04-02', '08:10:00');
As a result I want to get ALL timeslots of table site_timeslots with few additional info:
- for each site_timeslot I want to know count of site_teams in all related bookings to that timeslot in total (for example if there are 2 site_bookings for that site_timeslot and each has 2 site_teams, then total count should be 4) and also count of related bookings.
I have tried this sql:
SELECT `site_teams`.`id` AS site_teams_id, `site_teams`.`name` AS site_teams_name, `site_teams`.`booking_id` AS site_teams_booking_id, `site_days`.`id` AS site_days_id, `site_days`.`date` AS site_days_date, `site_timeslots`.`id` AS site_timeslots_id, `site_timeslots`.`starts` AS site_timeslots_starts, `site_bookings`.`id` AS site_bookings_id, `site_bookings`.`timeslot_id` AS site_bookings_timeslot_id
FROM (`site_days`)
LEFT JOIN `site_timeslots` ON `site_timeslots`.`day_id` = `site_days`.`id`
LEFT JOIN `site_bookings` ON `site_bookings`.`timeslot_id` = `site_timeslots`.`id`
LEFT JOIN `site_teams` ON `site_teams`.`booking_id` = `site_bookings`.`id`
GROUP BY `site_teams`.`booking_id`
-> but i won't get timeslots which haven't got any site_bookings, please how I should alter this sql query to have in result:
site_timeslot per row
count of site_bookings related to that site_timeslot in new column 'count_of_site_bookings'
count of site_teams related to all site_bookings that are related to that site_timeslot in new column 'count_of_site_teams'
You can do this by LEFT JOINing starting on site_timeslots and then using COUNT on the 2 relevant fields to get the totals you are after
SELECT
sti.*,
COUNT(DISTINCT sb.id) AS count_of_site_bookings,
COUNT(DISTINCT ste.id) AS count_of_site_teams
FROM site_timeslots sti
INNER JOIN site_days sd
ON sd.id = sti.day_id
LEFT JOIN site_bookings sb
ON sb.timeslot_id = sti.id
LEFT JOIN site_teams ste
ON ste.booking_id = sb.id
GROUP BY sti.id
You can find this on SQL Fiddle http://sqlfiddle.com/#!2/1a253/2
I also did a previous version which used a subquery due to an incorrect assumption on my part, if you'd like to take a look at that for reference it's available also at http://sqlfiddle.com/#!2/9ccf2/10

MYSQL SUM by QTY's And Values

I would like to know if its possible to get 2 sums from one query using the table values and then add them togther.
Here is some simple table & data which might help.
CREATE TABLE `cartcontents` (
`id` int(11) NOT NULL auto_increment,
`code` varchar(40) NOT NULL,
`qty` int(10) NOT NULL,
`price` decimal(30,2) NOT NULL,
`cart_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `zone` (`zone_code`,`cart_id`)
) ENGINE=MyISAM AUTO_INCREMENT=8 DEFAULT CHARSET=latin1;
-- ----------------------------
-- Records
-- ----------------------------
INSERT INTO `cartcontents` VALUES ('5', '011242077783866125432', '1', '36.00', '2');
INSERT INTO `cartcontents` VALUES ('4', '011242077793513596890', '3', '33.00', '4');
INSERT INTO `cartcontents` VALUES ('6', '011242077649557011493', '1', '110.00', '4');
INSERT INTO `cartcontents` VALUES ('7', '011242077724922511037', '1', '177.00', '5');
So I would like to be able collect the total qty & total value for a given cart_id.
So this would mean if I had 3 in the qty filed the sum would need to be (qty * price) for each zone then add them in total for the cart_id.
So in the above example if I was looking for the values for cart_id 4 The values I would hope I could return would be qty = 4 & total value = 209
Hope this makes sense and thanks if you can help.
Something like this should work:
SELECT SUM(qty) AS qty, SUM(qty * price) AS total
FROM cartcontents
GROUP BY cart_id

Categories