Two unrelated tables with match and against functions - php

How do I combine two unrelated tables into one SQL select statement request. However, both tables need to have the Match and Against functions for full text search. I'm getting a blank response and when I do a single table SQL match and against request it works fine but not when I do two tables.
Table One: transport - only id is a primary key integer auto_increment but the rest are varchar
+----+---------+-----------+--------------+
| id | title | type | tags |
+----+---------+-----------+--------------+
| 1 | triumph | motorbike | sport, black |
+----+---------+-----------+--------------+
| 2 | bmw | car | hatchback |
+----+---------+-----------+--------------+
Table Two: automobile - - only id is a primary key integer auto_increment but the rest are varchar
+----+-----------+-----------+------------+---------+
| id | name | kind | link | listed |
+----+-----------+-----------+------------+---------+
| 1 | suzuki | motorbike | /bike/new/ | green |
+----+-----------+-----------+------------+---------+
| 2 | volkwagan | car | /car/new/ | limited |
+----+-----------+-----------+------------+---------+
I need it to print out something like this (just a note, not sure how I would need id - perhaps two columns id_automobile and id_transport to references both above tables)
+----+-----------+-----------+------------+--------------+
| id | title | type | link | tags |
+----+-----------+-----------+------------+--------------+
| 1 | suzuki | motorbike | /bike/new/ | green |
+----+-----------+-----------+------------+--------------+
| 2 | triumph | motorbike | | sport, black |
+----+-----------+-----------+------------+--------------+
| 3 | bmw | car | | hatchback |
+----+-----------+-----------+------------+--------------+
| 4 | volkwagan | car | /car/new/ | limited |
+----+-----------+-----------+------------+--------------+
My failed attempt:
<table>
<tr>
<th>Title</th>
<th>Type</th>
<th>Link</th>
<th>Tags</th>
</tr>
if(isset($_GET['search'])) {
$search = $_GET['search'];
} else {
$search = '';
}
$sql = "SELECT * FROM `transport` WHERE MATCH(title, tags) AGAINST('".$search."') CROSS JOIN `automobile` WHERE MATCH(name, listed) AGAINST('".$search."')";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
// output data of each row
while($row = $result->fetch_assoc()) {
echo "<tr>";
echo "<td>".$row["title"]."</td><td>".$row["type"]."</td><td>".$row["link"]."</td><td>".$row["tags"]."</td>";
echo "</tr>";
}
} else {
echo "0 results";
}
$conn->close();
</table>
I would appreciate any help please

A UNION clause should give you the results that you need.
Just make sure that bost SELECTs, combined with UNION, have similar column sets. You can use AS to define aliases.
Something like this:
SELECT title, type, '' AS link, tags
WHERE MATCH(title, tags) AGAINST('...')
FROM transport
UNION
SELECT name AS title, kind AS type, link, listed AS tags
FROM automobile
WHERE MATCH(title, kind) AGAINST('...')

Related

PHP, MYSQL, select results based on all values from 3 dropdowns being true

I have 2 drop-down lists and one select box, Country (dropdown), region (dropdown), gender (select box x 2).
my database looks like this (i have cut down the number of values)
| id | england | usa | west | north | male | female | name | age |
| 1 | 1 | 0 | 1 | 0 | 0 | 1 | John | 33 |
| 2 | 0 | 1 | 0 | 1 | 0 | 1 | John | 56 |
Apart from the ID and additional values each value i need to query will be 1 or 0 (true or false)
the result i need is if someone selects england, west, male it brings back every row which has those values as true (their is extra information on these rows i need to display)
I just need some pointers on how to achive this i was thinking of using a lookup table but am struggling to use lookup table with multiple values, or do i just use php and set each value to its correct row name and do a query like that
First of all
I suspect you are mixing the schema (column names) and the values up in your database.
Your table should be more like
|id | country |region | gender |
--------------------------------
| 1 | usa | north | male |
| 1 | england | south | female |
Think about what properties the thing has that you're trying to model.
You already kind of have this in your drop-downs. Each drop-down has a list of possible values for that property.
While you're at it, you should probably go further and split your data into more tables.
countries
|id | name | other | columns | about | countries | eg. iso_code|
------------------------------------------------------------------
| 1 | USA | .... | ..... | ..... | ...... | us |
| 2 | England| .... | ..... | ..... | ...... | uk |
regions
| id | name |
------------------
| 1 | north |
| 2 | south |
| 3 | east |
| 4 | west |
| 5 | south-west|
| .. | ....
users
|id | name | country_id |region_id | gender |
---------------------------------------------
| 1 | John | 1 | 1 | m |
| 2 | Mary | 2 | 4 | f |
You would then have to come up with ways of converting your data form the old system into the new.
First take over some of the data from the original table
INSERT INTO new_users (id,name) SELECT id, name FROM old_users;
This will insert the names with the same IDs as the original table in the new table.
Create the data for the lookup tables (country and region in this case)
INSERT INTO countries (name,iso_code) VALUES
('USA','us'),
('United Kingdom','uk'),
....
Then update your fields
UPDATE new_users
FROM new_users INNER JOIN old_users ON old_users.id = new_users.id
SET new_users.country_id = 1 WHERE old_users.usa =1;
UPDATE new_users
FROM new_users INNER JOIN old_users ON old_users.id = new_users.id
SET new_users.country_id = 2 WHERE old_users.england =1;
...
etc...
UPDATE new_users
FROM new_users INNER JOIN old_users ON old_users.id = new_users.id
SET new_users.region_id = 1 WHERE old_users.north =1;
UPDATE new_users
FROM new_users INNER JOIN old_users ON old_users.id = new_users.id
SET new_users.region_id = 2 WHERE old_users.west =1;
...
Once you have that sorted...
Your drop-downs should be something like.. (you can generate the dropdowns automatically from your lookup tables (e.g. countries) by listing all the values with their names)
When you add new countries to the table, they will automatically appear in the drop-down from now on.
<?php
....
while ($resultrow = $result->fetch_assoc()){ ?>
<option value="<?php echo $resultrow['id'] ?>">
<?php echo $resultrow['name']; ?></option>
}
You should end up with something like the following in your html output.
<select>
<option value="1">USA</option>
<option value="2">UK</option>
</select>
Then your search query should look something like this:
$sql ="SELECT * FROM table
WHERE `country_id`= '$country_id'
AND `region_id`= '$region_id'
AND `gender`= '$gender'";

complex mysql query with custom sorting

I need to search following result .
singer_id=2
---------
B9 - song's list
song_au1
song10
p7 - song's list
songx
song11
11T- song list
song 35
The result is actully have following requirements.
1. show all songs by singer_id=2 order by (custom arrangement may be some or other table).
and because i'm using PHP, I want to show result the above format..
top - singer name
then it's album type
and all songs of that album
2nd album type
and all songs of that album
.....
I'm too much confused..
can somebody please tell me the best query!
table i've
================================================
| u_id | u_title | u_song_type | singer_id |
|================================================
| 1 | song1 | p7 | 1 |
| 2 | songx | p7 | 2 |
| 3 | songpo | p7 | 9 |
| 4 | song_dum3| 11T | 2 |
| 5 | song_01 | p7 | 3 |
| 6 | song_au1 | B9 | 2 |
| 7 | song11 | p7 | 2 |
| 8 | song35 | 11T | 1 |
| 9 | song10 | B9 | 2 |
-------------------------------------------------
Thank
After a long effort of hours. I have resolved it.
At the end I got It was easy.
$artistId = '2';
echo 'Singer Id:' . $row["artistName"];
//following query selects all records and sort records in a why i need that.
$sql2 = "SELECT * FROM album
ORDER BY
FIELD(u_song_type, 'B9','p7','11T')";
$result2 = mysqli_query($con,$sql2);
//An array is defined, to filter the title only once if
//repeated occurrence
$songTypesArray = array();
while($row2 = mysqli_fetch_array($result2)) {
if (in_array($row2['u_song_type'], $songTypesArray)) {
//if song Type is found in the array, skip it.
//I left it empty. if found in array
}
else{
//if song type is not found in the arry we'll push
// song type into array
array_push($songTypesArray,$row2['u_song_type']);
// song type only appears once if it is same
// in all song title.
echo $row2['u_song_type'];
}
//at the end song title appears.
echo $row2["u_title"];
}
}
This took whole night of mind in resolution and finally it is there. I hope people would get enough help from here
Thanks

MySQLi join and display details differently from 2 tables

Hello I have actually asked a similar question a while ago but only just realized I did not get an answer that solves my problem.
I have 2 tables in a MySQL DB, that are connected by the same main id, the following code is just a simplified example of the original code:
table1:
+-----------------------+
| main_id | name | type |
+-----------------------+
table2:
+----------------------------------------+
| main_id | secondary_id | color | price |
+----------------------------------------+
the result I want to achieve is to get every row of table 1, and under each one list all the linked by main id rows from table2, for example:
table1 rows:
+-------------------+
| 1 | name1 | type1 |
| 2 | name2 | type2 |
| 3 | name3 | type3 |
+-------------------+
table2 rows:
+----+------+----------+------+
| 1 | 23 | red | 500 |
| 1 | 24 | blue | 600 |
| 1 | 25 | green | 700 |
| 2 | 26 | pink | 400 |
| 2 | 27 | purple | 200 |
| 3 | 28 | white | 100 |
+----+------+----------+------+
result in display:
<h1 class="1">name1, type1</h1>
<div class="23">red,500</div>
<div class="23">red,500</div>
<div class="24">green,700</div>
<h1 class="2">name2, type2</h1>
<div class="25">pink,400</div>
<div class="26">purple,200</div>
And so on...I was using a while loop inside a while loop which wasn't giving me the required result, then I was advised to use MySQL JOIN, but when I do I get all values of the matching ids and cant display the headings only once and then list the related results under it, can someone please help me?
this is a simplified query i was using:
while($rows = $headings->fetch_array(MYSQLI_BOTH))
{
$id = $rows['id'];
$conts_q = $mysqli->query("SELECT * FROM `table2` WHERE id='$id'");
$conts_numr = $conts_q->num_rows;
if($conts_numr==0)
{
//Display empty
}
else
{
while($row2 = $conts_q->fetch_array(MYSQLI_BOTH))
{
//Get details and display
}
}
}
In your description, you use main_id, but in the code you use just id. Not sure which you're really using here - you will have to edit the code below to match your actual column names. If the database column name is actually main_id, then for instance the line with $id = $rows['id'] would have to be $rows['main_id']. Or it won't work.
while($rows = $headings->fetch_array(MYSQLI_BOTH))
{
echo '<h1 class="'.$rows['id'].'">'.$rows['name1'].', '.$rows['type'].'</h1>';
$id = $rows['id'];
$conts_q = $mysqli->query("SELECT * FROM `table2` WHERE id='$id'");
$conts_numr = $conts_q->num_rows;
if($conts_numr==0)
{
//Display empty
}
else
{
while($row2 = $conts_q->fetch_array(MYSQLI_BOTH))
{
if ($row2['id'] == $id) {
echo '<div class="'.$row2['secondary_id'].'">'.$row2['color'].', '.$row2['price'].'</div>';
}
}//while
}//else
}//while

Optimising SQL Queries

I'm developing a content management system at the moment, and I wanted to hear your thoughts on the following:
I have one table, page. Let's assume it looks like this
ID | Title | Content
1 | Test | This is a test
As well as this, I have a page_option table (so I can store options relating to the page, but I don't want to have a finite list of options - modules could add their own options to a page if required.)
The page_option table could look like this:
page_id | option_key | option_value
1 | background | red
1 | module1_key | chicken
Now to retrieve a page object, I do the following using the Active Record class (this was pseudo coded for this question):
function get_by_id($page_id) {
$this->db->where('id', $page_id);
$page_object = $this->db->get('page');
if($page_object->num_rows() > 0) {
$page = $page_object->row();
$this->db->where('page_id', $page_id);
$options_object = $this->db->get('option');
if($options_object->num_rows() > 0) {
$page->options = $options_object->result();
}
return $page;
}
return $page_object->row();
}
What I want to know, is there a way to do this in one query, so that the option keys become virtual columns in my select, so I'd get:
ID | Title | Content | background | module1_key
1 | Test | This is a test | red | chicken
In my results, rather than doing a seperate query for every row. What if there were 10,000? Etc.
Many thanks in advance!
Using the EAV (Entity-Attribute-Value) model you will always have to cope with these kind of issues. They're also not ver efficient due to the complexity of the queries (pivoting is required in most of them).
SELECT page_id,
MAX(CASE WHEN option_key = 'background' THEN option_value END) background,
MAX(CASE WHEN option_key = 'module1_key' THEN option_value END) module1_key,
MAX(CASE WHEN option_key = 'module2_key' THEN option_value END) module2_key
FROM page_option
GROUP BY page_id
For example, given this table:
| PAGE_ID | OPTION_KEY | OPTION_VALUE |
|---------|-------------|--------------|
| 1 | background | red |
| 1 | module1_key | chicken |
| 2 | module1_key | duck |
| 3 | module1_key | cow |
| 4 | background | blue |
| 4 | module2_key | alien |
| 4 | module1_key | chicken |
You will the following output:
| PAGE_ID | BACKGROUND | MODULE1_KEY | MODULE2_KEY |
|---------|------------|-------------|-------------|
| 1 | red | chicken | (null) |
| 2 | (null) | duck | (null) |
| 3 | (null) | cow | (null) |
| 4 | blue | chicken | alien |
Fiddle here.
Then just join with the page table and that's it :) I've omitted that part in order to focus the query in the grouping itself.
If you can add virtual fields with the activerecord class you can do something similar:
$this->db->add_field("(select group_concat(concat(option_key,':',option_value) SEPARATOR ' ') from page_option where page_id=$page_id group by page_id)");
It wont be optimal...
If option_key is uniqe per page_id (you don't have two or more background with page_id==1) you can do:
SELECT page.page_id, page.title, page.content,
GROUP_CONCAT(option_key SEPARATOR '#') AS option_keys,
GROUP_CONCAT(option_value SEPARATOR '#') as option_values,
FROM page
LEFT JOIN page_option ON page_option.page_id=page.page_id
WHERE page.page_id=USER_SPECIFIED_ID
You can execute this SQL-query and put its result into $result. After you should do every item of $result:
$result[$i]["options"] = array_combine(
explode("#",$result[$i]["option_keys"]),
explode("#",$result[$i]["option_values"])
);
You can do it with a foreach or you can use array_walk too.
After these you've an associative array with options in $result[$i]["options"]:
{
"background" => "red",
"module_key1"=> "chicken"
}
I hope it's what do you want.

I need to create a query using MySQL and PHP to get a result of two tables

I'm new to MySQL and PHP. I have two tables, one to hold all the company names and the other table has only the company name below the user:
Table 1
| # | Company name |
--------------------
| 1 | Microsoft |
| 2 | HP |
| 3 | Asus |
| 4 | Apple |
| 5 | Amazon |
| 6 | CCN |
table 2
| # | Company name | User name |
--------------------------------
| 1 | Asus | x1 |
| 2 | Apple | x1 |
| 3 | HP | x2 |
| 4 | Asus | x2 |
| 5 | Apple | x2 |
I need to create a query that achieves the following. First of all the companies are shown which are associated with a specific user (say Asus and Apple for user x1). After that, the remaining companies from table 1 are shown.
For example, the result of the query I'm looking for, for user X1 will display the rows in this way:
| # | Company name |
--------------------
| 1 | Asus |
| 2 | Apple |
| 3 | Microsoft |
| 4 | HP |
| 5 | Amazon |
| 6 | CCN |
How can I achieve this?
It looks like you want to include all companies, but for a given user, list the companies associated with that user first. If that's the case, you do not want to use an INNER JOIN.
Here's some SQL that should work. I've provided reasonable table and field names since you didn't give those. I'm also assuming that you have a reasonably sane table design with no duplicate rows.
SELECT c.company_name,
CASE
WHEN u.company_name IS NULL THEN 'N'
ELSE 'Y'
END AS user_has_company
FROM companies c
LEFT JOIN (
SELECT *
FROM users
WHERE user_name = 'x1'
) u
ON u.company_name = c.company_name
ORDER BY user_has_company DESC, c.company_name
This query will return an extra column - user_has_company. I'd use that to indicate whether the current user is associated with a given company, but you can ignore it if you want.
You will need a JOIN Statement to join another in the SELECT-Statement of table1
Quick example:
SELECT * FROM table2 INNER JOIN table1.id = table2.id WHERE table2.username = 'x1'
You'll find everything you need in the Documentation of JOINs.
http://dev.mysql.com/doc/refman/5.1/en/left-join-optimization.html
If you're just after the MySQL query for this then something like this would work
SELECT company_name,SUM(IF(user_name='x1',1,0)) as ordering
FROM `table2`
GROUP BY company_name
ORDER BY ordering DESC
But you should look at your schema before you go much further. If you have a column (company_name) in one table that refers to another table you should make that column refer to the PRIMARY KEY of the other table, i.e.
Table1
| # | company_name |
--------------------
| 1 | microsoft |
| 2 | hp |
| 3 | asus |
| 4 | apple |
| 5 | amazon |
| 6 | CCN |
table2
| # | company_id | user_name |
--------------------------------
| 1 | 3 | x1 |
| 2 | 4 | x1 |
| 3 | 2 | x2 |
| 4 | 3 | x2 |
| 5 | 4 | x2 |
This is one of the first things you learn in database design/normalisation. You will need to change your query in this case. Something like this:
SELECT company_name,SUM(IF(user_name='x1',1,0)) as ordering
FROM `table1`
LEFT JOIN `table2` ON table2.company_id=table1.id
GROUP BY company_name
ORDER BY ordering DESC
Create your query like this:
$sql = "SELECT b.companyName FROM table1 a INNER JOIN table2 b ON a.companyName = b.companyName WHERE b.userName = 'x1'";
Then, using PHP, use:
$con = mysql_connect("localhost","peter","abc123");
if (!$con)
{
die('Could not connect: ' . mysql_error());
}
mysql_select_db("my_db", $con);
$result = mysql_query($sql);
while($row = mysql_fetch_array($result))
{
echo $row['companyName'];
echo "<br />";
}
mysql_close($con);
Try this query:
SELECT company_name FROM table2 ORDER BY user_name ASC
In the HTML table, using PHP code:
$result = mysql_query(" SELECT company_name, user_name FROM table2 ORDER BY user_name ASC");
echo "<table>
<tr><th>Company Name</th><th>username</th></tr>";
while($row = mysql_fetch_array($result) {
echo "<tr><td>{$row['company_name']}</td><td>{$row['user_name']}</td></tr>";
}
echo "</table>"

Categories