how to combine multiple select query into one? - mysql

i have three tables with structure
CREATE TABLE IF NOT EXISTS `refrence` (
`products_ref_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`categories_id` int(11) NOT NULL,
`Product_property` varchar(255) NOT NULL,
`Product_reference` varchar(50) NOT NULL,
PRIMARY KEY (`products_ref_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=7 ;
CREATE TABLE IF NOT EXISTS `product_details` (
`products_id` int(11) NOT NULL AUTO_INCREMENT,
`categories_id` int(11) NOT NULL,
`FieldA` varchar(30) NOT NULL,
`FieldB` varchar(50) NOT NULL,
`FieldC` varchar(255) NOT NULL,
`FieldD` varchar(255) NOT NULL,
`FieldE` varchar(255) NOT NULL,
`FieldF` varchar(255) NOT NULL,
`Field_desc` text NOT NULL,
PRIMARY KEY (`products_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=98 ;
Here i am extracting Product_reference value from refrence table with respect to Product_property & categories_id as
SELECT Product_reference FROM refrence where categories_id=3 AND Product_property ='xxx'
Now this Product_reference is the field name in product_details table suppose result is abc. So i want to extract distinct abc from product_details table as
SELECT Distinct abc FROM product_details where categories_id=3
Now i want to combine both the query to one, What is the way to write these queries in to single one.
I tried this
SELECT Distinct (
SELECT Product_reference FROM refrence where categories_id=3 AND Product_property ='xxx'
) as aa FROM product_details where categories_id=3
But its not working, may be i am missing some syntax.

Without knowing what isn't working, it would appear that you're trying to accomplish this:
SELECT r.product_reference
FROM refrence AS r
LEFT JOIN categories AS c ON (c.categories_id = r.categories_id AND r.categories_id=3 AND r.product_property='zzz')
WHERE c.categories_id=1
As pointed out by Eggyal, this will always return nothing because of the impossible condition of category_id=1 AND category_id=3, so either:
They both have to be 1 or both have to be 3
OR
They're completely different "categorys" that are unrelated, or just happen to have the same names.

Related

I need to optimize tables and queries

I have 3 tables: info, data, link, there is a request for data:
select *
from data,link,info
where link.info_id = info.id and link.data_id = data.id
offer optimization options:
a) tables
b) request.
Queries for creating tables:
CREATE TABLE info (
id int(11) NOT NULL auto_increment,
name varchar(255) default NULL,
desc text default NULL,
PRIMARY KEY (id)
) ENGINE=MyISAM DEFAULT CHARSET=cp1251;
CREATE TABLE data (
id int(11) NOT NULL auto_increment,
date date default NULL,
value INT(11) default NULL,
PRIMARY KEY (id)
) ENGINE=MyISAM DEFAULT CHARSET=cp1251;
CREATE TABLE link (
data_id int(11) NOT NULL,
info_id int(11) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=cp1251;
Thanks!
Never use commas in the FROM clause. Always use proper, explicit, standard, readable JOIN syntax:
select *
from data d join
link l
on l.data_id = d.id join
info i
on l.info_id = i.id;
Second, for this query your indexes are probably fine. I would also recommend a primary key index on link:
CREATE TABLE link (
data_id int(11) NOT NULL,
info_id int(11) NOT NULL,
PRIMARY KEY (data_id, info_id)
);
This is a good idea in general, even if it is not specific to this query.

i get wrong results from mysql join query

I have 2 tables, that i want to join, one is rooms and another is reservations.
Basically I want to search for rooms which are not reserved (not in reservation table) and to get the details of those rooms (which are not in reservation table) from room table.
Here are my tables structure:
CREATE TABLE `room` (
`roomID` int(11) NOT NULL AUTO_INCREMENT,
`hotelID` int(11) NOT NULL,
`roomtypeID` int(11) NOT NULL,
`roomNumber` int(11) NOT NULL,
`roomName` varchar(255) NOT NULL,
`roomName_en` varchar(255) NOT NULL,
`roomDescription` text,
`roomDescription_en` text,
`roomSorder` int(11) NOT NULL,
`roomVisible` tinyint(4) NOT NULL,
PRIMARY KEY (`roomID`)
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8;
CREATE TABLE `reservation` (
`reservationID` int(11) NOT NULL AUTO_INCREMENT,
`customerID` int(11) NOT NULL,
`hotelID` int(11) NOT NULL,
`reservationCreatedOn` datetime NOT NULL,
`reservationCreatedFromIp` varchar(255) CHARACTER SET greek NOT NULL,
`reservationNumberOfAdults` tinyint(4) NOT NULL,
`reservationNumberOfChildrens` tinyint(4) NOT NULL,
`reservationArrivalDate` date NOT NULL,
`reservationDepartureDate` date NOT NULL,
`reservationCustomerComment` text CHARACTER SET greek,
PRIMARY KEY (`reservationID`)
) ENGINE=InnoDB AUTO_INCREMENT=47 DEFAULT CHARSET=utf8;
CREATE TABLE `reservationroom` (
`reservationroomID` int(11) NOT NULL AUTO_INCREMENT,
`reservationID` int(11) NOT NULL,
`hotelID` int(11) NOT NULL,
`roomID` int(11) NOT NULL,
PRIMARY KEY (`reservationroomID`)
) ENGINE=InnoDB AUTO_INCREMENT=47 DEFAULT CHARSET=utf8;
Here is the query that I have right now, which gives me wrong results:
SELECT * FROM room r
LEFT JOIN reservation re
ON r.hotelID = re.hotelID
WHERE re.hotelID = 13
AND NOT
(re.reservationArrivalDate >= '2014-07-07' AND re.reservationDepartureDate <= '2014-07-13')
I also have created a fiddle, with the data from both tables included:
http://sqlfiddle.com/#!2/4bb9ea/1
Any help will be deeply appreciated
Regards, John
i agree that room number was missed,
but query template should looks like
SELECT
*
FROM
room r
LEFT JOIN reservation re
ON r.hotelID = re.hotelID
WHERE r.hotelID = 2
AND NOT (
re.hotelID IS NOT NULL
AND re.reservationArrivalDate >= '2014-07-07'
AND re.reservationDepartureDate <= '2014-09-23'
) ;
You need change table in where statement from reservation to room. Also you need add re.hotelID to where statement as well, because on where statement you need check that record is not null ans only after try to check dates
Given the newly-added reservationroom table, consider using a NOT EXISTS sub-query to find rooms without reservations:
SELECT
*
FROM
room r
WHERE NOT EXISTS
(SELECT
*
FROM
reservationroom rr
WHERE
rr.reservationroomID = r.roomID
)

how to create a view from three tables

I have problem with getting combined records from 3 tables.
Here is the structure of the tables
CREATE TABLE IF NOT EXISTS `adds` (
`addid` int(11) NOT NULL AUTO_INCREMENT,
`addtypeid` varchar(45) NOT NULL,
`addcreatedon` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`addtitle` varchar(255) DEFAULT NULL,
`addtext` text NOT NULL,
PRIMARY KEY (`addid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=40 ;
CREATE TABLE IF NOT EXISTS `adds_filters` (
`addfilterid` int(11) NOT NULL AUTO_INCREMENT,
`addid` int(11) NOT NULL,
`filterid` int(11) NOT NULL,
PRIMARY KEY (`addfilterid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=40 ;
CREATE TABLE IF NOT EXISTS `categories_filters` (
`filterid` int(11) NOT NULL AUTO_INCREMENT,
`catid` varchar(45) NOT NULL,
`filtername` varchar(45) NOT NULL,
`sorder` int(11) DEFAULT NULL,
`visible` int(11) DEFAULT NULL,
PRIMARY KEY (`filterid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=230 ;
Adds have one to many relationship with adds_filters. That is, one add can have more then one filter.
What I need is the following:
I would like to create a view which when select * would return all rows from adds, together with filterid(s) and respective filtername(s). Please note that one add may have many filterid(s)
Can anyone help me with this?
Regards
You do not need a view.
I think you want to use a combination of LEFT OUTER JOIN and GROUP_CONCAT(). That way you will get 1 result for each row in the adds table, along with a list of related filter_ids and filter_names, if any.
Something like this:
select adds.addid, adds.addtypeid, adds.addcreatedon, adds.addtitle, adds.addtext,
group_concat(adds_filters.filterid) as filter_ids,
group_concat(categories.filtername) as filter_names
from adds
left outer join adds_filters on adds_filters.addid = adds.addid
left outer join categories_filters on categories_filters.filterid = adds_filters.filterid
group by adds.addid, adds.addtypeid, adds.addcreatedon, adds.addtitle, adds.addtext;
create view v1 as
select adds.addid as addid, categories_filters.filtername as filtername, categories_filters.filterid as filterid
from adds inner join adds_filters on adds.addid = adds_filters.addid
inner join categories_filters on categories_filters.filterid = adds_filters.filterid

How to optimize this query as the in array seems to slow things down significantly

I am looking to find out the best way to optimize a query like this:
SELECT
a.ID,
a.ECPCodeID,
a.RegDate,
a.BusName,
a.City,
a.AccountNum,
b.ID as RepCodeID,
b.RepCode
FROM ECPs_Registration a,
Reps_Codes b
WHERE (SUBSTR(a.PostalCode,1,5)IN(SELECT
SUBSTR(Zip,1,5)
FROM Reps_Zip
WHERE RepCodeID = b.ID)
AND a.AccountNum NOT IN(SELECT
ShipTo
FROM Reps_ShipTo))
OR a.AccountNum IN(SELECT
ShipTo
FROM Reps_ShipTo
WHERE RepCodeID = b.ID)
ORDER BY b.RepCode,a.BusName,a.City
I know there are more factors involved such as indexes and such, I just am asking about the query part of it for now. Mainly, since I have to go through the Reps_ShipTo and Reps_Zip tables for tons of records. I thought about changing something like:
a.AccountNum NOT IN (SELECT ShipTo FROM Reps_ShipTo)
INTO
(SELECT count(*) FROM Reps_ShipTo WHERE a.AccountNum = ShipTo) = 0
Not sure if that is proper or if there is a better way. Any help would be appreciated. Thanks.
EDIT:
Schema:
CREATE TABLE IF NOT EXISTS `ECPs_Codes` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`ECPCode` char(4) NOT NULL,
PRIMARY KEY (`ID`),
KEY `ECPCode` (`ECPCode`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ;
CREATE TABLE IF NOT EXISTS `ECPs_Registration` (
`RegDate` datetime NOT NULL,
`ID` int(10) NOT NULL AUTO_INCREMENT,
`ECPCodeID` int(11) NOT NULL,
`FirstName` varchar(200) NOT NULL,
`LastName` varchar(200) NOT NULL,
`BusName` varchar(200) NOT NULL,
`Address` varchar(200) NOT NULL,
`Address2` varchar(200) NOT NULL,
`City` varchar(100) NOT NULL,
`Province` char(2) NOT NULL,
`Country` varchar(100) NOT NULL,
`PostalCode` varchar(10) NOT NULL,
`Email` varchar(200) NOT NULL,
`AccountNum` int(8) NOT NULL,
PRIMARY KEY (`ID`),
KEY `ECPCodeID` (`ECPCodeID`),
KEY `PostalCode` (`PostalCode`),
KEY `AccountNum` (`AccountNum`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
CREATE TABLE IF NOT EXISTS `Reps_Codes` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`Name` varchar(50) NOT NULL,
`RepCode` varchar(16) NOT NULL,
`AllAccess` tinyint(4) NOT NULL,
PRIMARY KEY (`ID`),
KEY `RepCode` (`RepCode`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
CREATE TABLE IF NOT EXISTS `Reps_ShipTo` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`RepCodeID` int(11) NOT NULL,
`ShipTo` varchar(20) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`ID`),
KEY `RepID` (`RepCodeID`),
KEY `ShipTo` (`ShipTo`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE IF NOT EXISTS `Reps_Zip` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`RepCodeID` int(11) NOT NULL,
`Zip` varchar(10) NOT NULL,
PRIMARY KEY (`ID`),
KEY `RepCodeID` (`RepCodeID`),
KEY `Zip` (`Zip`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
There are two things that massively hurt performance on your query.
You are joining two tables by combining multiple conditions, each needing subqueries
You're doing a join on two tables using SUBSTR(Zip,1,5)=SUBSTR(postalcode,1,5)
The logic behind your query seems to be something like:
For every ECPs_Registration find the matching record in Rep_Codes
using the following rules:
If there is a matching record in Reps_ShipTo, to for that registration, use that table to look it up (primary match)
If there isn't a matching record in Reps_ShipTo, seek through Reps_Zip for a matching RepCode by Zipcode-match (secondary)
Now if the above fully describes your situation, you should probably start off by redesigning your database.
The Reps_ShipTo table creates a 0:N relationship between ECPs_Registration and Rep_Codes. Such relations don't need an extra table - they can simply be stored as nullable foreign keys - in your case a RepCodeId in ECPs_Registration would do the trick, and would remove the entire Reps_ShipTo table from the database.
You should probably also create (yes, redundant) extra columns that only store the first 5 letters of the zip codes in both ECPs_Registration and Reps_Zip. This will allow simple equality matches instead of the SUBSTR-functions. Or, you might decide to do this match only once for every record, and store the result in above RepCodeId, which totally eliminates the dual join.
The following query assumes you for some reason don't want to or can't change your database:
SELECT
a.ID, a.ECPCodeID, a.RegDate, a.BusName, a.City, a.AccountNum,
CASE (b1.ID IS NOT NULL, b1.ID, b2.ID) as RepCodeID,
CASE (b1.ID IS NOT NULL, b1.RepCode, b2.RepCode) as MyRepCode
FROM ECPs_Registration a
LEFT JOIN Reps_ShipTo ON (Reps_ShipTo.Shipto=a.AccountNum)
LEFT JOIN Rep_Codes b1 ON (b1.ID=Reps_ShipTo.RepCodeId)
LEFT JOIN Reps_Zip ON (SUBSTR(Zip,1,5)=SUBSTR(a.postalcode,1,5))
LEFT JOIN Rep_Codes b2 ON (b2.ID=Reps_Zip.RepCodeID)
ORDER BY MyRepCode,a.BusName,a.City
Without your database schema and sample data, I have no way to test if above query actually works and has the same result as your original.
SELECT
a.ID,
a.ECPCodeID,
a.RegDate,
a.BusName,
a.City,
a.AccountNum,
b.ID as RepCodeID,
b.RepCode
FROM ECPs_Registration a, Reps_Codes b
INNER JOIN Reps_Zip as r on SUBSTR(a.PostalCode,1,5) = SUBSTR(r.Zip,1,5)
LEFT JOIN Reps_ShipTo as rs on a.AccountNum = rs.ShipTo
LEFT JOIN ShipTo as s on a.AccountNum = s.ShipTo
WHERE (s.id is null or rs.id is null)
ORDER BY b.RepCode,a.BusName,a.City

View help. Pulling data from 3 tables

Okay, I need some major help with this subject. This is what I need the view to do. It needs to take Sum of the DKP_Change Column in the Attendance table
SELECT SUM(a.DKP_Change) FROM Attendance AS a GROUP BY Name
add the value of the initial DKP from the characters table
SELECT b.Inital_DKP FROM Characters AS b GROUP BY Name
Subtract the sum of the raid drops tabe cost
SELECT SUM(c.Cost) FROM Raid_Drops AS c GROUP BY Name
I'm entirely new to the idea of VIEWS and i'm not sure where to begin with, the name of the view should be DKP, the columns should be Name and Total_DKP, where total dkp is calculated from teh above select statements.
Here are the creates for all 3 tables.
CREATE TABLE `Attendance` (
`Date` date NOT NULL,
`Name` varchar(20) NOT NULL,
`Hours` int(11) NOT NULL,
`Penalty` float NOT NULL,
`Rank` set('Raider','Core','Elite') NOT NULL,
`Rate` int(11) NOT NULL,
`DKP_Change` float NOT NULL,
`RecordNumber` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`RecordNumber`)
) ENGINE=MyISAM AUTO_INCREMENT=15 DEFAULT CHARSET=latin1
CREATE TABLE `Characters` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`Name` varchar(25) NOT NULL,
`Class` varchar(25) NOT NULL,
`Spec` varchar(25) NOT NULL,
`Position` set('Healer','Tank','DPS') NOT NULL COMMENT 'Healer, Tank, or DPS',
`Usable` set('Cloth','Mail','Plate') NOT NULL COMMENT 'Type of Usable Armor? Cloth, Mail, Or Plate',
`Primary Stat` set('Agility','Strength','Intellect','Healer','Tank') NOT NULL COMMENT 'Used for Sorting Only(ie dps trinket with agility strength dps not eligible)',
`Initial_DKP` int(11) NOT NULL COMMENT 'DKP given at the start of current tier.',
`Total_DKP` int(11) NOT NULL COMMENT 'Huge Complicated Mess.',
PRIMARY KEY (`ID`)
) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=latin1
CREATE TABLE `Raid_Drops` (
`Record Number` int(11) NOT NULL,
`Date` date NOT NULL,
`Name of Item` varchar(25) NOT NULL,
`Item Slot` enum('Main Hand','Off Hand','Head','Neck','Shoulder','Back','Chest','Wrist','Hands','Waist','Legs','Feet','Ring 1','Ring 2','Trinket 1','Trinket 2') NOT NULL,
`Player_Name` varchar(25) NOT NULL,
`Cost` float NOT NULL,
PRIMARY KEY (`Record Number`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
You could
Join the three tables in a subselect, grouping on Name
Perform your calculations on the results of each subselect
The only part that's not entirely clear to me is if the names in Characters are unique or not. If they are, you can drop the group by. If they are not, the AVG might give you unexpected results.
SQL Statement
SELECT sumA
, initialB
, sumC
, sumA + initialB - sumC
, a.Name
FROM (
SELECT Name, SUM(DKP_Change) AS sumA
FROM Attendance
GROUP BY Name
) AS a
INNER JOIN (
SELECT Name, Inital_DKP AS initialB
FROM Characters
) AS b ON a.Name = b.Name
INNER JOIN (
SELECT Name, SUM(Cost) AS sumC
FROM Raid_Drops
GROUP BY Name
) AS c ON c.Name = b.Name