I need to filter duplicates, but union is displaying duplicates.
For example Query-1 is displaying 5 tuples like 1,2,3,4,5.
Query-2 generating 3 tuples like 1,2,6.
Union of both the tuples displaying result 1,2,3,4,5,1,2,6.
But I want the result as 1,2,3,4,5,6.
Here is my controller :
public function product()
{
$product = $this->input->post('keyword');
$temp = explode(" ", $product);
$count = count($temp);
for($i=0;$i<$count;$i++)
{
$query = "SELECT * FROM `product` WHERE SOUNDEX(`name`) LIKE CONCAT('%',SOUNDEX('$temp[$i]'),'%') UNION SELECT * FROM `product` WHERE `name` like '%$temp[$i]%'";
$data = $this->Back_model->getby_query($query);
$records = json_encode($data);
echo $records;
}
}
There is no apparent reason for using 2 select queries, the second filter may be added to an existing where clause
SELECT *
FROM `product`
WHERE SOUNDEX(`name`) LIKE CONCAT('%',SOUNDEX('$temp[$i]'),'%')
AND `name` like '%$temp[$i]%'";
First of all, I would probably do this in another scripting language, but if you really want to do this in MySQL, you need to use DISTINCT. You should query the data and put it in a temp table, and from the temp table query the DISTINCT values. Once you're done you can drop the temp table. For an operation this small, not sure if this is what I would do, but if you say that you have thousands of records/values that need to be filtered, than it might be worth it.
Related
I use Sphinx with Yii2 and need to query with filter by jSON field.
$query = new \yii\sphinx\Query();
$query->from('announcements');
$query->addSelect("*");
$query->addSelect(new Expression("IN(filters['color'], 'blue', 'red', 'green') AS f_color"));
$query->where("is_active = 1");
$query->andWhere("f_color = 1");
$announces = $query->all();
There is jSON field filters in my Sphinx index. For example:
[filters] => {"brand":"Toyota","model":"Prius","color":"red","price":"12000"... etc]
It works OK. But now I need to make a pagination... and there is a problem when I try to count records before $query->all()
$count = $query->count(); // Return error "no such filter attribute 'f_color'"
Generated query was:
SELECT COUNT(*) FROM announcements WHERE ( is_active = 1 ) AND ( f_color = 1 )
count() by default replaces the select part with * and this is where your alias is defined hence the error.
There are different ways to achieve it like:
use ActiveDataProvider like described here,
use META information like described here
Since you want to make a pagination I would go with the first example.
So i have this result row from a query with GROUP_CONCAT:
clients, employees, employees, providers, providers
And i wanna get something like this:
clients, employees, providers
Please, i'm new here and i need your help, be pacient if the question is not well formed
Use the DISTINCT option in GROUP_CONCAT()
SELECT GROUP_CONCAT(DISTINCT columnname), ...
Source: http://php.net/manual/en/function.array-unique.php
array_unique — Removes duplicate values from an array
array array_unique ( array $array [, int $sort_flags = SORT_STRING ] )
maybe this is what you need:
$row = array_unique($row);
Edit: If I am not mistaken, sql returns the results as a key value array, so I think this is what you want.
Edit2: Do this:
$row = explode(",", $response);
$row = array_unique($row);
[major edit to make things clear]
I want to write a query that returns a dynamic column name like this:
SELECT
f2 AS
(
SELECT column_name
FROM column_names_tbl
WHERE column_name = "experience"
limit 0,1
)
FROM some_table
so that would output the same as this:
SELECT
f2 AS experience
FROM some_table
This is no correct SQL syntax, even because the two queries (the selected field and it's alias) are both subqueries and unrelated to each other. So, there's also no possibility for mysql to distinguish what name you want to connect to what value, even if the syntax was correct...
You already use a more or less normalized relational table, so I suggest the following solution:
you select the revision ID and name in a separate query; store them in PHP and use them for whatever you want
next, you evaluate the following query into a separated result set: SELECT ps.keyname, psv.keyvalue FROM page_setting_values AS psv INNER JOIN page_settings AS ps ON ps.id = psv.setting_id WHERE psv.page_revision_id = :revision with :revision representing your revision id
you may now assemble an associated array from that result set:
$settings = [];
$result = $db->executeQuery('...')->fetchAll();
foreach($result as $setting)
{
$settings[$setting['keyname']] = $setting['keyvalue'];
}
Hope that helps ;)
I have a fairly large dataset and a query that requires two joins, so efficiency of the query is very important to me. I need to retrieve 3 random rows from the database that meet a condition based on the result of a join. Most obvious solution is pointed out as inefficient here, because
[these solutions] need a sequential scan of all the table (because the random value associated with each row needs to be calculated - so that the smallest one can be determined), which can be quite slow for even medium sized tables.
However, the method suggested by the author there (SELECT * FROM table WHERE num_value >= RAND() * (SELECT MAX(num_value) FROM table) LIMIT 1 where num_value is ID) doesn't work for me because some IDs might be missing (because some rows may have been been deleted by users).
So, what would be the most efficient way to retrieve 3 random rows in my situation?
EDIT: the solution does not need to be pure SQL. I also use PHP.
Since you don't want many results, there are a couple of interesting options using LIMIT and OFFSET.
I'm going to assume an id column which is unique and suitable for sorting.
The first step is to execute a COUNT(id), and then select random 3 numbers from 0 to COUNT(id) - 1 in PHP. (How to do that is a separate question, and the best approach depends on the number of rows total and the number you want).
The second step has two options. Suppose the random numbers you selected are 0, 15, 2234. Either have a loop in PHP
// $offsets = array(0, 15, 2234);
foreach ($offsets as $offset) {
$rows[] = execute_sql('SELECT ... ORDER BY id LIMIT 1 OFFSET ?', $offset);
}
or build a UNION. Note: this requires sub-selects because we're using ORDER BY.
// $offsets = array(0, 15, 2234);
$query = '';
foreach ($offsets as $index => $offset) {
if ($query) $query .= ' UNION ';
$query .= 'SELECT * FROM (SELECT ... ORDER BY id LIMIT 1 OFFSET ?) Sub'.$index;
}
$rows = execute_sql($query, $offsets);
Adding your RAND() call into the ORDER BY clause should allow you to ignore the ID. Try this:
SELECT * FROM table WHERE ... ORDER BY RAND() LIMIT 3;
After having performance issues pointed out, your best bet may be something along these lines (utilizing PHP):
$result = PDO:query('SELECT MAX(id) FROM table');
$max = $result->fetchColumn();
$ids = array();
$rows = 5;
for ($i = 0; $i < $rows; $i++) {
$ids[] = rand(1, $max);
}
$ids = implode(', ', $ids);
$query = PDO::prepare('SELECT * FROM table WHERE id IN (:ids)');
$results = $query->execute(array('ids' => $ids));
At this point you should be able to select the first 3 results. The only issue with this approach is dealing with deleted rows and you might have to either bump the $rows var or add some logic to do another query in case you didn't receive at least 3 results back.
I need to return a single row with some datas taken from some tables not related each others.
So, for example, my actual queries are these (I done it trought a PHP script) :
$query=mysql_query("SELECT trackid FROM tracklist WHERE usersub='".$_SESSION['nickname']."'",$mydb);
echo mysql_num_rows($query);
$query=mysql_query("SELECT trackid FROM comments WHERE usercom='".$_SESSION['nickname']."'",$mydb);
echo mysql_num_rows($query);
$query=mysql_query("SELECT vote FROM vote WHERE uservote='".$_SESSION['nickname']."'",$mydb);
echo mysql_num_rows($query);
$query = mysql_query("SELECT datereg FROM users WHERE nickname='".$_SESSION['nickname']."'",$mydb);
echo mysql_result($query,0,'datereg');
But this will call the MySql server 4 times.
Whats your suggestion to better this situation?
If the tables are not related then you will have to make 4 seperate calls
If the tables COULD be related by foreign keys then you could join them in some way and possibly cut down your sql calls
Ultimately though if you need all of the data then you'll have to request it from the database
You could use a UNION. And, btw, mysql_result is poor. And FFS don't forget to sanitize your inputs!
<?php
$nickname = mysql_escape_string($_SESSION['nickname']);
$sql = "
SELECT COUNT(trackid) AS n FROM tracklist WHERE usersub='{$nickname}'
UNION
SELECT COUNT(trackid) FROM comments WHERE usercom='{$nickname}'
UNION
SELECT COUNT(vote) FROM vote WHERE uservote='{$nickname}'
UNION
SELECT datereg FROM users WHERE nickname='{$nickname}'
";
$result = mysql_query($sql, $db);
while ($row = mysql_fetch_assoc($result)) {
echo $row['n'];
}
?>
I wouldn't really recommend this as it's a bit of a mess combining "count" values with a date in the same column, but you can do it. It's the direct answer to your question.
Well, you could create a fifth table and use it as an index.
If all the values { trackid, vote, datareg } are integers, the index table could contain three columns - nickname, value, and table. When you add records to one of the other tables, add a corresponding record to the index table.
For example,
INSERT INTO vote (vote, uservote, ...) VALUES (123, 'abc', ...);
INSERT INTO myindex (nickname, nvalue, ntable) VALUES ('abc', 123, 'vote');
(I wouldn't actually store the table name as a string but as a numeric value, but you get the idea)
Then on a query, you just SELECT nvalue, ntable FROM myindex WHERE nickname = 'abc';
You will possibly get more than one row.
I think that this is a lot of work and you are better off sticking with the four original queries.
Have you tried combining the select statement together like
SELECT .. Actually.
Maybe you should normalise your database and set up links between your tables...
Edit :: And i'm not sure how you're preparing yourself against mysql injection, but be careful with where your $_SESSION[] comes from
If all the selects return a single row:
$query=mysql_query("
(SELECT trackid FROM tracklist WHERE usersub='".$_SESSION['nickname']."'") as tracklist,
(SELECT trackid FROM comments WHERE usercom='".$_SESSION['nickname']."'") as trackid,
(SELECT vote FROM vote WHERE uservote='".$_SESSION['nickname']."'") as vote,
(SELECT datereg FROM users WHERE nickname='".$_SESSION['nickname']."'") as datereg
"