PHP/MySQL Search code and logic for relational database schema - php

I have created this database schema and with help from several users on here, I have a database which takes user submitted business entries stored in the business table, which are additionally grouped under one or several of about 10 catagories from the catagories table, in the tbl_works_catagories table by matching the bus_id to the catagory id.
For example, bus_id 21 could be associated with catagory_id 1, 2, 5, 7, 8.
CREATE TABLE `business` (
`bus_id` INT NOT NULL AUTO_INCREMENT,
`bus_name` VARCHAR(50) NOT NULL,
`bus_dscpn` TEXT NOT NULL,
`bus_url` VARCHAR(255) NOT NULL,
PRIMARY KEY (`bus_id`)
)
CREATE TABLE `categories` (
`category_id` INT NOT NULL AUTO_INCREMENT,
`category_name` VARCHAR(20) NOT NULL,
PRIMARY KEY (`category_id`)
)
CREATE TABLE `tbl_works_categories` (
`bus_id` INT NOT NULL,
`category_id` INT NOT NULL
)
Now, what i want to do next is a search function which will return businesses based on the catagory. For example, say one of the businesses entered into the business table is a bakers and when it was entered, it was catagorised under Food (catagory_id 1) and take-away (catagory_id 2).
So a visitor searches for businesses listed under the Food catagory, and is returned our friendly neighbourhood baker.
As with all PHP/MySQL, i just can't (initially anyway) get my head around the logic, never mind the code!

You should setup foreign keys in your tables to link them together.
CREATE TABLE `business` (
`bus_id` INT NOT NULL AUTO_INCREMENT,
`bus_name` VARCHAR(50) NOT NULL,
`bus_dscpn` TEXT NOT NULL,
`bus_url` VARCHAR(255) NOT NULL,
PRIMARY KEY (`bus_id`)
)
CREATE TABLE `categories` (
`category_id` INT NOT NULL AUTO_INCREMENT,
`category_name` VARCHAR(20) NOT NULL,
PRIMARY KEY (`category_id`)
)
CREATE TABLE `tbl_works_categories` (
`bus_id` INT NOT NULL,
`category_id` INT NOT NULL,
FOREIGN KEY (`bus_id`) REFERENCES business(`bus_id`),
FOREIGN KEY (`category_id`) REFERENCES categories(`category_id`)
)
Then your search query would be something like:
SELECT b.*
FROM business b, categories c, tbl_works_categories t
WHERE
b.bus_id = t.bus_id AND
c.category_id = t.category_id AND
c.category_id = *SOME SEARCH VALUE*
which using JOIN would be written as:
SELECT b.*
FROM business b
JOIN tbl_works_categories t
ON b.bus_id = t.bus_id
JOIN categories c
ON c.category_id = t.category_id
WHERE c.category_id = *SOME SEARCH VALUE*

Maybe you want something like this:
SELECT `bus_id` FROM `tbl_works_categories` WHERE `category_id` = *some id from the search*
AND `category_id` = *some other id from the search*;
Although you'd need those ids- there are a few ways to do this, I'll describe probably the most straight forward...
You get categories from $_POST, so let's just say you have 2 of them entered. (Food, and take-away). Parse these however you want, there are multiple ways, but the point is they're coming from $_POST.
execute this sort of thing for each one you find:
SELECT `category_id` FROM `categories` WHERE `category_name` LIKE '%*the name from $_POST*%';
Store these results in an array...based on how many you have there you can build an applicable query similar to the one I describe first. (Keep in mind you don't need and AND there, that's something you have to detect if you return > 1 category_id from the second query here)
I'm not going over things like security..always be careful when executing queries that contain user submitted data.
An alternate solution might involve a join, not too sure what that'd look like off the top of my head.
Good luck.

If you want all businesses that are related to the given category-id, your SQL-statement would look something like this:
SELECT `business`.`bus_name`
FROM `business`
WHERE `business`.`bus_id` = `tbl_works_categories`.`bus_id`
AND `categories`.`category_id` = `tbl_works_categories`.`category_id`
AND `categories`.`category_id` = 1;
Where 1 in this case is your food-category, but could be your PHP variable where the ID of the category the user selected is stored.
And one hint: Be sure to name your tables either in plurar or in singular. You are mixing both and could get confused.

Related

MYSQL will not return more than 1 category

I've tried to find an answer to this problem, but I can't.
I have a 3 table format mqsql database.
I use 1 table to add all of the product information, CarpetInfo,
1 Table to list my categories, CarpetCategories,
and 1 Table to add categories to the products, CarpetCategorySort.
My CarpetCategorySort table has 3 columns, Manufacturer, Style, CategoryID.
Example would be Manufacturer = Aladdin, Style = Alma Mater, CategoryID = 14/ 15/ 18/ 19/ 20/ 21/ 67/
My CarpetCategories Table has 2 Columns CategoryID and Category.
2 Examples would be CategoryID = 14, Category = Commercial &
CategoryID = 15, Category = Commercial Loop
I can only get the code to work when I type in Commercial into the $category variable below. The code will not work if I type Commercial Loop into the $category variable. It's like it will only pull in the first number 14 and all of the others are ignored. The pricing order and everything else works right, just not the CategoryID part.
Here is my code.
<?php $mill = "Aladdin"; $category = "Commercial Loop";
$order = mysqli_query($con, "
SELECT * FROM CarpetInfo JOIN CarpetCategorySort USING (Manufacturer, Style)
JOIN CarpetCategories USING (CategoryID)
WHERE Manufacturer='$mill' AND Category LIKE '%$category%'
order by Price = 0, Price asc,
Style asc");
include($_SERVER['DOCUMENT_ROOT'].'/includes/pricing/carpet-order-test.htm');?>
Any help is greatly appreciated!
That's a backward way of handling things, a field with several datapoints smooshed together like that really never has any justification for existence. I'd list the carpets in one table, list the categories in another, and finally list cross-references of both in another table, where you get a many-to-one relationship at both ends.
You need an actual category table only if you think it's going to take so much room to give duplicate info for each category and/or you can't control user input for categories (like you aren't just using a pulldown to give a name choice).
Something like:
CREATE TABLE IF NOT EXISTS `carpets` (
`id` int(11) NOT NULL,
`name` varchar(50) NOT NULL,
`abbrev` varchar(10),
`description` varchar(250),
[...]
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
CREATE TABLE IF NOT EXISTS `carpet_categories` (
`id` int(11) NOT NULL,
`carpet_id` int(11) NOT NULL,
`category_id` int(11) NOT NULL,
[...]
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
CREATE TABLE IF NOT EXISTS `carpet_category_info` (
`id` int(11) NOT NULL,
`price-per-sqf` int(11) NOT NULL,
`name` varchar(50),
[...]
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
then all your joins become simple, and fast.. And accurate.

Assign a unique ID to each name in a table where names are repeated

I have a table that contains millions of sales records and looks like this:
CREATE TABLE `sales` (
`dollar_amount` INT NULL,
`transaction_date` DATE NULL,
`company_name` VARCHAR(45) NULL,
`company_id` INT NULL);
The first three columns are populated with data. I would like to insert data into the company_id column that will identify each company with an auto_incremented integer. I plan to use the company_id field as a foreign key referencing another table that will contain each company's details. Many companies have multiple transactions, so the code needs to assign the same company_id to each row in the sales table with a matching company_name.
Is there a way to do this using only MySQL?
First, I'd recommend creating the company table:
CREATE TABLE company (
company_id INT NOT NULL AUTO_INCREMENT,
company_name VARCHAR(45),
PRIMARY KEY(company_id));
Then insert the companies from your sales data:
INSERT INTO company (company_name)
SELECT distinct company_name
FROM sales;
Finally, update your sales table with a join to get the company_id:
UPDATE sales s
JOIN company c ON s.company_name = c.company_name
SET s.company_id = c.company_id;
SQL Fiddle Demo
You should also remove the company_name field from the sales table since this is now stored in the company table.
To define an auto incremented integer, you just use the AUTO_INCREMENT keyword. However, if you define any columns as auto_increment, you must also make that column your primary key. Which, in this case, would make sense in order for it to be a foreign key elsewhere.
Try this:
CREATE TABLE `sales` (
`dollar_amount` INT NULL,
`transaction_date` DATE NULL,
`company_name` VARCHAR(45) NULL,
`company_id` INT NOT NULL AUTO_INCREMENT,
PRIMARY KEY(company_id);
SQL Fiddle

MYSQL join two tables

I have two tables one containing a selection of values in different categories and the other ‘master’ table referencing the text values by the first primary key.
Table 1
CREATE TABLE IF NOT EXISTS `defaultvalues` (
`default_ID` int(11) NOT NULL AUTO_INCREMENT,
`columnName` varchar(100) NOT NULL,
`defaultValue` varchar(100) NOT NULL,
PRIMARY KEY (`default_ID`),
UNIQUE KEY `columnName` (`columnName`,`defaultValue`)
)
Table 2
CREATE TABLE IF NOT EXISTS `master` (
`master_ID` int(11) NOT NULL AUTO_INCREMENT,
`size` int(11) NOT NULL,
`madeby` int(11) NOT NULL,
`type` int(11) NOT NULL,
`colour` int(11) NOT NULL,
`notes` text NOT NULL,
`issueDate` datetime NOT NULL,
`ceMark` text NOT NULL,
`batchNumber` text NOT NULL,
PRIMARY KEY (master_ID)
)
The master.size for each row is a P.key in the defaultvalues table.
E.g. master.colour = 234, 234=defaultvalues.defaultValue = ‘red’
E.g. master.size = 345, 345=defaultvalues.defaultValue = ‘small’
Now I would like to run a query that returns the ‘master’ table with text values in columns colour, size, type, madeby from ‘defaultvalues. defaultValue’ and ready for further processing.
I have been trying with sub queries and temp tables but I can’t get it to work
The current system relies on PHP and multiple queries and building arrays.
There has to be a more elegant solution.
I hope this makes sense.
Any hints or advice much appreciated.
Dave
You'll need to join the master table to the defaultvalues table multiple times. Something like this:
SELECT m.*, d.defaultvalue as sizevalue, d2.defaultvalue as colorvalue...
FROM master m
JOIN defaultvalues d ON m.size = d.default_id
JOIN defaultvalues d2 ON m.color = d2.default_id
...
What i did in the end.... while it works I am still not happy. There must be something better...
SELECT m.*,
(SELECT defaultValue FROM defaultvalues WHERE default_ID = m.colour) AS myColour ,
(SELECT defaultValue FROM defaultvalues WHERE default_ID = m.size) AS mySize
FROM master m
WHERE m.master_ID = 1;

SQL - After receiving rows of the same data from a SELECT INNER JOIN with a WHERE...How do I take one time what is different / unique

I can use LIMIT to surrender myself to one row but I would like to learn how I can provide one of each rows rather than the several of the same rows / data
Goto : http://inks-etc.com/Script/SQL/loginform.php
Username: jason
Password: 123
Sounds like you have this setup:
create table `some_table` (
`uniq_id` bigint(20) unsigned not null auto_incremenet,
`some_data` varchar(200) not null,
`some_other_data` varchar(100) not null,
PRIMARY KEY (`uniq_id`)
) ENGINE=MyISAM AUTO_INCREMENT=260285 DEFAULT CHARSET=utf8;
create table `some_other_table` (
`other_id` bigint(20) unsigned not null auto_incremenet,
`link_to_uniq_id` bigint(20) unsigned not null,
`multiple_entry_data` varchar(100) not null,
PRIMARY KEY (`uniq_id`)
) ENGINE=MyISAM AUTO_INCREMENT=260285 DEFAULT CHARSET=utf8;
Where some_other_table can match some_table multiple times. It also sounds like you are trying something like this, and wanting one row per uniq_id:
select * from some_table
inner join some_other_table
on some_table.uniq_id = some_other_table.link_to_uniq_id
The way that you can modify this type of query to get only one entry per uniq_id is something like this, using the group by directive:
select * from some_table
inner join some_other_table
on some_table.uniq_id = some_other_table.link_to_uniq_id
group by some_table.uniq_id
Hopefully I understood your question, and hopefully this answers it.

mysql 'likes' structure table

I'm working on a web site where users can post articles with this table structure :
CREATE TABLE IF NOT EXISTS `articles` (
`id_articles` int(10) unsigned NOT NULL AUTO_INCREMENT,
`id_users` int(10) unsigned NOT NULL,
`articles` text NOT NULL,
PRIMARY KEY (`id_articles`),
UNIQUE KEY `id_articles` (`id_articles`),
KEY `id_users` (`id_users`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
Each user can 'like' the articles.
Is that the right way below to create a 'like table' :
CREATE TABLE IF NOT EXISTS `articles_likes` (
`id_articles` int(10) unsigned NOT NULL,
`id_users` int(10) unsigned NOT NULL,
KEY `id_articles` (`id_articles`,`id_users`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
It is correct but you will want to add separte indexes on id_articles and id_users (also you might want to name the columns 'id_article' and 'id_user' for sanity).
CREATE TABLE IF NOT EXISTS `article_likes` (
`id_article` int(10) unsigned NOT NULL,
`id_user` int(10) unsigned NOT NULL,
KEY `id_article` (`id_article`),
KEY `id_user` (`id_user`)
) ENGINE=InnoDB;
The reason you want separate indexes is because in mysql if you create an index on columns (A, B) that index will be used in queries having in the where clause column A, or columns A and B.
In your case for example if you made a query "SELECT * FROM article_likes WHERE id_user=X" this query would not use an index.
An ever better option would be to add a combined index and a separate index on the second column from the combined index. Like this:
CREATE TABLE IF NOT EXISTS `article_likes` (
`id_article` int(10) unsigned NOT NULL,
`id_user` int(10) unsigned NOT NULL,
KEY `id_article_user` (`id_article`, `id_user`),
KEY `id_user` (`id_user`)
) ENGINE=InnoDB;
This way you would have optimal performance on queries like 'WHERE id_user=X', "WHERE id_article=X', "WHERE id_article=X AND id_user=Y"
This is a valid way Chris. You can use COUNT() to match the id_articles in the articles_likes table against the current article you are viewing in articles.
$articles_id = 23;
mysql_query("SELECT COUNT(*) FROM articles_likes
WHERE id_articles = ".$articles_id);
You can also just leave COUNT() (MySQL) out and instantly know which users are the "likers" of the articles and use count() (PHP) on the returned Array to duplicate the effect of COUNT() in MySQL.
i would have a total of 3 tables. an articles table, and the user id could be a column in that for users who submit articles , but you need a separate user table since not all users will submit articles (i am assuming), and then a 3rd table for likes, that takes the primary key from users and the primary key from articles and uses them as foreign keys. so each time an article is liked, an entry is made in the 3rd table

Categories