Assistance with MySQL JOIN - mysql

I have two tables, one with categories and subcategories. Each category and subcategory has an id and if it's a subcategory, it's got a topid != 0 referring what it's a subcategory of. The other table "markers" has a field 'cat' which correlates with the category field 'name' Now I want to select everything from markers with category.id = 4 OR category.topid = 4 so I tried this query:
SELECT * FROM `xymply_markers`
JOIN `xymply_categories`
ON xymply_markers.cat = xymply_categories.name
WHERE xymply_categories.topid=4
OR xymply_categories.id=4
Which doesn't return me anything even tho I do have such elements in my table "markers". Any assistance would be appreciated!
Table schemas:
`xymply_categories` (
`id` int(11) NOT NULL auto_increment,
`topid` int(11) NOT NULL,
`name` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=15 DEFAULT CHARSET=utf8 AUTO_INCREMENT=15 ;
`xymply_markers` (
`created` date NOT NULL,
`id` int(11) NOT NULL auto_increment,
`sdate` date NOT NULL,
`hdate` date NOT NULL,
`name` varchar(60) NOT NULL,
`address` varchar(80) NOT NULL,
`unit` varchar(6) NOT NULL,
`lat` decimal(10,7) NOT NULL,
`lng` decimal(10,7) NOT NULL,
`type` varchar(30) NOT NULL,
`userid` int(11) NOT NULL,
`adtext` text NOT NULL,
`phone` varchar(20) NOT NULL,
`email` varchar(30) NOT NULL,
`url` varchar(30) NOT NULL,
`cat` varchar(4) NOT NULL,
UNIQUE KEY `id` (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=151 DEFAULT CHARSET=utf8 AUTO_INCREMENT=151 ;
Sample Data:
xymply_categories:
id 1
topid 0
name 'vehicle'
--------------
id 2
topid 1
name 'bike'
--------------
id 3
topid 1
name 'truck'
xymply_markers:
id 1
sdate 2012-03-01
hdate 2012-04-01
name 'TEST'
address '1234 TEST'
unit''
lat 49.0
lng -123.0
adtext 'TEST'
phone '1234567890'
email 'email#email.com'
url 'www.url.com'
cat 'bike'
--------------
id 1
sdate 2012-03-01
hdate 2012-04-01
name 'TEST'
address '1234 TEST'
unit''
lat 49.5
lng -123.5
adtext 'TEST'
phone '1234567890'
email 'email#email.com'
url 'www.url.com'
cat 'vehicle'

One problem is that the xymply_markers.cat field is VARCHAR(4) but the xymply_categories.name field is TEXT, and contains values longer than 4 characters. Either you're not giving us the accurate schema, or you're confused about which columns join, or you're never going to see any trucks or vehicles. Columns which join should have the same type almost without exception (I've never seen a good reason for an exception).
You are then asking about id = 4 or topid = 4, but the sample data you show only has id = 1 or topid = 1. Do you actually have data where id = 4 or topid = 4 in the system?
Between these two lots of confusion, it is hard to know what we're up against. If you have data that joins and has the relevant topid or id values, then your query should work.
I have a field called 'id' in both tables. How can I control which one I'm accessing with PHP after I read data into the array with $row = #mysql_fetch_assoc($result)?
The simplest way is to ensure that each result column has a unique name, creating one with an 'alias', as in:
SELECT c.id AS category_id,
c.topid,
c.name AS category_name,
m.id AS marker_id,
m.name AS marker_name,
...
PHP will associate the alias names with the the data in the row.

Related

How to get null column when condition doesn't apply with multiple rows results

I am having a hard time trying to figure out how to get the follow query result:
Let me show you the table structure and the query I am using. I think am close to get it right but I need some help figuring out what is wrong:
Here are the tables I have:
CREATE TABLE `manager` (
`man_id` int(11) NOT NULL AUTO_INCREMENT,
`man_firtname` varchar(20) NOT NULL,
`man_lastname` varchar(20) NOT NULL,
PRIMARY KEY (`man_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
man_id man_firtname man_lastname
1 Albert Einstein
CREATE TABLE `orders` (
`ord_id` int(11) NOT NULL AUTO_INCREMENT,
`ord_orderno` varchar(12) NOT NULL,
`ord_man_id` int(11) NOT NULL,
`ord_total` decimal(11,0) NOT NULL,
`ord_code` varchar(10) NOT NULL,
PRIMARY KEY (`ord_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ord_id ord_orderno ord_man_id ord_total ord_code
1 ABCDE 1 160 FFFBBB
CREATE TABLE `orders_items` (
`ori_id` int(11) NOT NULL AUTO_INCREMENT,
`ori_ord_id` int(11) NOT NULL,
`ori_item_code` varchar(10) NOT NULL,
`ori_name` varchar(40) NOT NULL,
`ori_desc` varchar(80) NOT NULL,
PRIMARY KEY (`ori_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ori_id ori_ord_id ori_item_code ori_name ori_desc
1 1 JO123 JohnyT This is a test description
2 1 KK234 SprayC Spray test description
CREATE TABLE `proda` (
`pra_id` int(11) NOT NULL AUTO_INCREMENT,
`pra_code` varchar(10) NOT NULL,
`pra_name` varchar(40) NOT NULL,
PRIMARY KEY (`pra_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
pra_id pra_code pra_name
1 JO123 JohnyT
CREATE TABLE `prodb` (
`prb_id` int(11) NOT NULL AUTO_INCREMENT,
`prb_code` varchar(10) NOT NULL,
`prb_name` varchar(40) NOT NULL,
PRIMARY KEY (`prb_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
prb_id prb_code prb_name
1 KK234 SprayC
CREATE TABLE `special` (
`spe_id` int(11) NOT NULL AUTO_INCREMENT,
`spe_man_id` int(11) NOT NULL,
`spe_code` varchar(10) NOT NULL,
PRIMARY KEY (`spe_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
spe_id spe_man_id spe_code spe_item_code
1 1 FFFBBB JO123
This is the query I have:
SELECT
tbl1.ord_id,
UPPER(tbl1.ord_orderno) As ord_orderno,
tbl1.ord_total,
tbl1.ord_code,
tbl2.ori_id,
tbl2.ori_item_code,
tbl3.pra_name,
tbl4.prb_name
FROM
orders tbl1
JOIN
orders_items tbl2
ON
tbl1.ord_id=tbl2.ori_ord_id
LEFT JOIN
proda tbl3
ON
tbl2.ori_item_code=tbl3.pra_code
LEFT JOIN
prodb tbl4
ON
tbl2.ori_item_code=tbl4.prb_code
JOIN
special tbl5
ON
tbl1.ord_code=tbl5.spe_code
WHERE
tbl1.ord_code IN (SELECT spe_code FROM special JOIN manager ON man_id=1)
AND
tbl1.ord_id=1;
And this is the result I get:
ord_id ord_orderno ord_total ord_code ori_id ori_item_code pra_name prb_name
1 ABCDE 160 FFFBBB 1 JO123 JohnyT
1 ABCDE 160 FFFBBB 2 KK234 SprayC
What I am trying to get instead?
ord_id ord_orderno ord_total ord_code ori_id ori_item_code pra_name prb_name
1 ABCDE 160 FFFBBB 1 JO123 JohnyT
1 ABCDE 160 NULL 2 KK234 SprayC
Basically, the ord_code should only show when there is a match in the special table, otherwise it should be null. Anyone has any idea on what I am doing wrong? Thank you so much
Use tbl5.spe_code instead of tbl1.ord_code in the SELECT list. When there's no match, the LEFT JOIN will return NULL for all the columns in the special table.
You also need to change the columns you're using in the join with special. it should be tbl2.ori_item_code = tbl5.spe_item_code.
And you need to use LEFT JOIN with the special table in order to get non-matching rows.
SELECT
tbl1.ord_id,
UPPER(tbl1.ord_orderno) As ord_orderno,
tbl1.ord_total,
tbl5.spe_code,
tbl2.ori_id,
tbl2.ori_item_code,
tbl3.pra_name,
tbl4.prb_name
FROM
orders tbl1
JOIN
orders_items tbl2
ON
tbl1.ord_id=tbl2.ori_ord_id
LEFT JOIN
proda tbl3
ON
tbl2.ori_item_code=tbl3.pra_code
LEFT JOIN
prodb tbl4
ON
tbl2.ori_item_code=tbl4.prb_code
LEFT JOIN
special tbl5
ON
tbl2.ori_item_code=tbl5.spe_item_code
WHERE
tbl1.ord_code IN (SELECT spe_code FROM special JOIN manager ON man_id=1)
AND
tbl1.ord_id=1;
DEMO

MYSQL LEFT JOIN Returning Null

I have three tables ,
Table 1 & table 2
Need to compare : component_name with product and component_version with version
if those values are same then fetch corresponding cvid from table2
Table 2 & table 3
Now with respect to the table 2 - cvid value is equal to table 3 - cvid value
(in-sence values should be equal) exact string match
i have tried with tables
Table 1 : upload_bom
CREATE TABLE IF NOT EXISTS `upload_bom` (
`component_name` varchar(100) NOT NULL,
`component_version` varchar(20) NOT NULL
)
Table 2 : cpe_cse
CREATE TABLE IF NOT EXISTS `cpe_cse` (
`id` varchar(20) NOT NULL,
`cpe` varchar(20) NOT NULL,
`argument` varchar(20) NOT NULL,
`vendor` varchar(100) NOT NULL,
`product` varchar(100) NOT NULL,
`version` varchar(20) NOT NULL,
`subversion` varchar(20) NOT NULL,
`platform` varchar(100) NOT NULL,
`cvid` varchar(20) NOT NULL
)
Table 3: cses
CREATE TABLE IF NOT EXISTS `cses` (
`cvid` varchar(20) NOT NULL,
`cvss` varchar(20) NOT NULL,
`description` varchar(5000) NOT NULL
)
Hence i have tried an code ,
but when i try to join cpe_csv.cvid = cses.cvid , i get null values but the same query works in sqlite not in MySQL
below is the query i tried
SELECT DISTINCT upload_bom.component_name, upload_bom.component_version, cpe_cse.cvid, cses.cvid, cses.description
FROM upload_bom
LEFT JOIN cpe_cse on upload_bom.component_name = cpe_cse.product AND upload_bom.component_version = cpe_cse.version
LEFT JOIN cses on cpe_cse.cvid = cses.cvid
i have to display something like
Select upload.bom_Component_name, upload_bom.component_version, cpe_cse.cvid, cses.cvid, cses.description
component_name , component_version , cpe_cse.cvid, cses.cvid, cses.description
"freebsd","1.1","cv1999-0001","cv1999-0001", "this is an software"
while joining two columns of two tables iam getting null values , i wann to over come it and join the tables

MYSQL - Select and parse

I have my databse: public
I have my table: info
in row files of player Maria i have this:
['python22.dll', ''], ['python27.dll', ''], ['channel.inf', ''], ['devil.dll', ''],['is_hack.exe', '']
The first 4 is normal so I don't want to see them in the list .. i just want to catch the "is_hack.exe"
My mysql query to get all ( including my normal files) is:
query("SELECT files FROM public.info WHERE player = 'Maria' ORDER BY actual_time DESC LIMIT 0,1;")
I need to see all the names that are not mine. Like:
FILE_FROM_OUTSIDE1 = is_hack.exe
FILE_FROM_OUTSIDE2 = stackoverflow.dll
If you know about LUA, i can get the entire query results to LUA then begin to parse.. but how?
EDIT:
This is my table:
CREATE TABLE `info` (
`id` int(6) NOT NULL AUTO_INCREMENT,
`player` varchar(12) DEFAULT NULL,
`type_check` varchar(10) DEFAULT NULL,
`normal` varchar(20) DEFAULT NULL,
`actual` int(3) DEFAULT NULL,
`actual_time` varchar(20) DEFAULT NULL,
`files` varchar(3000) DEFAULT NULL,
PRIMARY KEY (`id`)
In "files" i have all this:
['python22.dll', ''], ['python27.dll', ''], ['channel.inf', ''], ['devil.dll', ''],['is_hack.exe', '']
I just want to select the is_hack.exe .. like: print is_hack.exe
I'm not sure if this is what you want. But i think this might help:
Replace the filename_field with your col name.
query("SELECT files FROM public.info WHERE player = 'Maria' AND filename_field = 'is_hack.exe' ORDER BY actual_time DESC LIMIT 0,1;")
UPDATE
I don't know if this I'm right but you should not save data like this. You can create a files table and specify which user own each row. Like:
CREATE TABLE `playerfiles` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`player` int(11) DEFAULT NULL,
`filename` varchar(60) DEFAULT NULL,
PRIMARY KEY (`id`)
);
Then you can retrieve data with JOIN.
SELECT * FROM `info`
JOIN `playerfiles` ON `playerfiles.player` = `info.id`
WHERE `info.player` = 'Maria' and `playerfiles.filename` = 'THE NAME'

Optimize Mysql query with boolean value

I have this table:
CREATE TABLE IF NOT EXISTS `products` (
`product_id` int(11) NOT NULL AUTO_INCREMENT,
`supplier_id` int(11) NOT NULL,
`allowed` varchar(256) NOT NULL,
`blocked` varchar(256) NOT NULL,
`approved` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`product_id`),
KEY `supplier_id` (`supplier_id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
'approved' is a boolean 0/1 field
'blocked' and 'allowed' hold country codes such as "US CA FR"
I run this query:
SELECT DISTINCT supplier_id
FROM products
WHERE (
supplier_id=0 OR
supplier_id = 1207077 OR
supplier_id = 1207087 OR
supplier_id = 1207079 OR
supplier_id = 1207082 OR
supplier_id = 1207083 OR
supplier_id = 1207086 OR
supplier_id = 1207084 OR
supplier_id = 1207078 OR
supplier_id = 1207085 OR
supplier_id = 1207094 OR
supplier_id = 1207097 OR
supplier_id = 1207095 OR
supplier_id = 1207089 OR
supplier_id = 1207091
) AND (
(`blocked` NOT LIKE '%US%' AND `allowed` ='') OR
`allowed` LIKE '%US%'
) AND approved=1;
It runs in about 0.02s. Any suggestions on how to optimize it? Thank you.
The execution speed is the same because OR and non left anchored LIKE clauses cannot use indexes appropriately. You've got bad table design in that US FR etc field, that should be in another table that you join against. If you are stuck with your design and the table is vey large, then create a derived table for the supplier_id OR clauses and then JOIN against the same table in order to find the rest of the matches. This may also require a UNION since you have other OR's. For more information:
http://dev.mysql.com/doc/refman/5.6/en/index-btree-hash.html
I managed to optimize it as follows:
SELECT DISTINCT supplier_id FROM products WHERE ((`blocked` NOT LIKE '%US%' AND
`allowed` ='') OR `allowed` LIKE '%US%') AND approved=1 AND supplier_id IN (1207077,
1207087, 1207079, 1207082, 1207083, 1207086, 1207084, 1207078, 1207085, 1207094,
1207097, 1207095, 1207089, 1207091);
It runs at 0.0004s now.
Thank you winmutt for pointing me to the right direction :-)

Optimize tables MySQL

I have a query that is executed in 35s, which is waaaaay too long.
Here are the 3 tables concerned by the query (each table is approx. 13000 lines long, and should be much longer in the future) :
Table 1 : Domains
CREATE TABLE IF NOT EXISTS `domain` (
`id_domain` int(11) NOT NULL AUTO_INCREMENT,
`domain_domain` varchar(255) NOT NULL,
`projet_domain` int(11) NOT NULL,
`date_crea_domain` int(11) NOT NULL,
`date_expi_domain` int(11) NOT NULL,
`active_domain` tinyint(1) NOT NULL,
`remarques_domain` text NOT NULL,
PRIMARY KEY (`id_domain`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Table 2 : Keywords
CREATE TABLE IF NOT EXISTS `kw` (
`id_kw` int(11) NOT NULL AUTO_INCREMENT,
`kw_kw` varchar(255) NOT NULL,
`clics_kw` int(11) NOT NULL,
`cpc_kw` float(11,3) NOT NULL,
`date_kw` int(11) NOT NULL,
PRIMARY KEY (`id_kw`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Table 3 : Linking between domain and keyword
CREATE TABLE IF NOT EXISTS `kw_domain` (
`id_kd` int(11) NOT NULL AUTO_INCREMENT,
`kw_kd` int(11) NOT NULL,
`domain_kd` int(11) NOT NULL,
`selected_kd` tinyint(1) NOT NULL,
PRIMARY KEY (`id_kd`),
KEY `kw_to_domain` (`kw_kd`,`domain_kd`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
The query is as follows :
SELECT ng.*, kd.*, kg.*
FROM domain ng
LEFT JOIN kw_domain kd ON kd.domain_kd = ng.id_domain
LEFT JOIN kw kg ON kg.id_kw = kd.kw_kd
GROUP BY ng.id_domain
ORDER BY kd.selected_kd DESC, kd.id_kd DESC
Basically, it selects all domains, with, for each one of these domains, the last associated keyword.
Does anyone have an idea on how to optimize the tables or the query ?
The following will get the last keyword, according to your logic:
select ng.*,
(select kw_kd
from kw_domain kd
where kd.domain_kd = ng.id_domain and kd.selected_kd = 1
order by kd.id_kd desc
limit 1
) as kw_kd
from domain ng;
For performance, you want an index on kw_domain(domain_kd, selected_kd, kw_kd). In this case, the order of the fields matters.
You can use this as a subquery to get more information about the keyword:
select ng.*, kg.*
from (select ng.*,
(select kw_kd
from kw_domain kd
where kd.domain_kd = ng.id_domain and kd.selected_kd = 1
order by kd.id_kd desc
limit 1
) as kw_kd
from domain ng
) ng left join
kw kg
on kg.id_kw = ng.kw_kd;
In MySQL, group by can have poor performance, so this might work better, particularly with the right indexes.