Here is my Table
Id | No |Group
1 | 1 |Alpha
1 | 1,2 |Alpha
1 | 2,4,5|Alpha
How can i find the the row which has No as 5 using laravel eloquent
$Match = MyModel::whereIn('No', array(5))->get();
But it didn't return any rows.
When i try to see the query executed it shows me
select * from `table` where `No` in (5)
How can i do this in php and laravel
As a pure Eloquent workround, you might be able to do something like:
$id = 5
$Match = MyModel::with(array('No' => function($query) use($id) {
$query->where_id($id);
}))->get();
Using Raw and FIND_IN_SET, something like:
$Match = MyModel::whereRaw(
'find_in_set(?, `No`)',
[5]
)->get();
(Untested)
But this will never be an efficient query because it can't use indexes; and there are many other reasons why a comma-separated list is a bad idea (such as lack of referential integrity)
The real solution will always be to normalize your database properly
Related
I have a problem in Laravel where I want to with a specific package to show something to these users?!
This is the existing code:
$package = DB::table('users')->where('package_id', '=', '2')->value('*');
And this brings me back all users with all the packages, but I just want the user with package number 2 and show something??
This is a query on the controller.
On the frontend, I just examined the variable.
Thanks guys
$package = DB::table('users')->where('package_id', '=', '2')->get() should suffice.
I can't see the advantage of appending value('*') in this scenario
Try this... I hope it will work sure
$package = DB::table('users')->select('*')->where('package_id', '=', '2')->get();
And this brings me back all users with all the packages, but I just
want the user with package number 2
I assume you mean you only want to get users with package_id 2 and nothing else.
If so the needed SQL query is harder.
Note that the query and demo is based on the information you have provided which is not alot
Query
SELECT
*
FROM
users
WHERE
users.id IN (
SELECT
users.id
FROM
users
GROUP BY
users.id
HAVING
SUM(users.package_id = 2) = 1
AND
COUNT(users.package_id = 2) = 1
)
Result
| id | package_id |
| --- | ---------- |
| 1 | 2 |
| 3 | 2 |
Also note that this query assumes that package_id's within user_id's are unique.
see demo
With DB Facade
$packages = DB::table('users')->where('package_id', '=', '2')->get();
With Eloquent
$packages = User::where('package_id', '2')->get();
Blade
#if($packages->count() > 0) //or #if(!$packages->isEmpty())
// if part
#else
// else part
#endif
Remember get() method always return collections
first() method return instance of a model
If you are using first() method instead of get() then you can handle something like that
Controller
$package = User::where('package_id', '2')->first();
Blade
#if($package) //or #if(!is_null($package))
// code...
#endif
I am trying to get how many names do I have in database. For this purpose I am using Query Builder like this:
$namesIdsCount = DB::table('names_to_options')
->select('name_id')
->groupBy('name_id')
->havingRaw($having)
->count();
Is says that 24, which is not correct, because if I will write code like this:
$namesIdsCount = DB::table('names_to_options')
->select('name_id')
->groupBy('name_id')
->havingRaw($having)
->get();
result object contains 247 elements, which is correct. I have tried to play with skip/take, but still no results. Where am I wrong? Thanks for any help.
I think it's the other way around, you're not getting 24 groups. You're getting 24 elements within the first group. That configuration results in the following query:
SELECT
COUNT(*) AS 'aggregate',
`name_id`
FROM `names_to_options`
WHERE EXISTS(
{your $havingRaw sub-query}
)
GROUP BY `name_id`;
What you end up with will look something like this:
+---------------+---------+
| aggregate | name_id |
+---------------+---------+
| 24 | 1 |
+---------------+---------+
| 5 | 2 |
+---------------+---------+
| 30 | 3 |
+---------------+---------+
| ... and so on | 4 |
+---------------+---------+
Query\Builder just doesn't realize you can get more than one result back when count() is involved.
You were pretty close to the right answer yourself though.
$namesIdsCount = DB::table('names_to_options')
->select('name_id')
->groupBy('name_id')
->havingRaw($having)
->get();
get() returns an Eloquent\Collection, child of Support\Collection, which has its own version of the count method. So your answer is just:
$namesIdsCount = DB::table('names_to_options')
->select('name_id')
->groupBy('name_id')
->havingRaw($having)
->get()
->count();
If you really want this to happen in MySQL, the query you want to happen would look like this:
SELECT COUNT(*) FROM (
SELECT
`name_id`
FROM `names_to_options`
WHERE EXISTS(
{your $havingRaw sub-query}
)
GROUP BY `name_id`
) AS temp;
For that, you can do this:
$query = DB::table('names_to_options')
->select('name_id')
->groupBy('name_id')
->havingRaw($having);
$sql = $query->toSql();
$values = $query->getBindings();
$count = DB::table(DB::raw('('.$sql.') AS `temp`'))
->selectRaw("COUNT(*) AS 'aggregate'", $values)
->first()
->aggregate;
MySQL performance can get a little hairy when asking it to write temp-tables like that though, so you'll have to experiment to see which option is faster.
Inuyaki is right
(id, name_id),
(1,1),
(2,1),
(3,2),
(4,3)
There are are four rows so get() method will return 4 rows
but there are three groups if you use groupBy [name_id]
1 (1,1)
2 (2)
3 (3)
now count will return 3
hope this will help.
My ch_skills table looks like
uid | skill1 | skill2 | skill3 | skill4 | skill5
1 1 2 2 0 1
2 1 1 2 1 1
3 1 2 3 0 1
My first question: is this correct? I mean would it be better if I made it like this:
uid | skillid | skill_lvl
1 1 1
1 2 2
1 3 2
1 4 0
1 5 1
Everything worked fine until now with the example #1, but now I'm in a trouble with the sql queries. Currently, I'm using 5 different queries to get the level of each skill. I use the following code:
For skill1:
$query = $this->db->prepare("SELECT `skills`.`skill_ID` as `Skill1_id`,
`skill_name`.`skill_name` as `Skill1_name`, `skill_level` as `Skill1_level`,
`skill_price` as `Skill1_price`
FROM `skills`, `skill_name`, `ch_skills`
WHERE `skill_name`.`skill_ID` = `skills`.`skill_ID`
AND `skills`.`skill_ID`= 1
AND `skills`.`skill_level` = `ch_skills`.`skill1`
AND `ch_skills`.`uid` = :uid");
For skill2:
$query = $this->db->prepare("SELECT `skills`.`skill_ID` as `Skill1_id`,
`skill_name`.`skill_name` as `Skill1_name`, `skill_level` as `Skill1_level`,
`skill_price` as `Skill1_price`
FROM `skills`, `skill_name`, `ch_skills`
WHERE `skill_name`.`skill_ID` = `skills`.`skill_ID`
AND `skills`.`skill_ID`= 2
AND `skills`.`skill_level` = `ch_skills`.`skill2`
AND `ch_skills`.`uid` = :uid");
And so on... As you can see, there's only two differences: skill_id = 2, and skill2 as the coulmn's name. Is there any way for querying all the 5 skills in only 1 query? Or would you recommend me anyway to change the table structure?
Note: skills stands for the skill prices, and skill_name for the skill's names.
As the other commenters have suggested, your best choice is to change the table exactly as you proposed.
The biggest reason not to have a wide table like you show in your first example, is that adding a skill means changing the structure of the database, which could break existing queries.
Secondly, as you see when you're trying to query the results, having a single table doesn't even make it easier to work with.
The only possible benefit to a non-normalized table like your example is that it takes up slightly less disk space. But in todays world, disk space should never be your primary concern.
To answer your question about querying the original non-normalized example, however, there are two ways to do it:
Use a union statement which would combine 5 distinct queries together. This is pretty inefficient
Create a table with (in this case) 5 rows (or if you have a Skills table use that). Then join the ch_skills table to that, which should take each row and split it 5 times. See below: (note: I'm assuming for the purposes of this example that skills and skill_name are in a 1:1 relationship and only have 5 records each)
SELECT skills.skill_ID,
skill_name.skill_name,
skill_level as Skill_level,
skill_price as Skill_price
FROM skills
JOIN skill_name on skill_name.skill_ID = skills.skill_ID
JOIN ch_skills
WHERE ch_skills.uid = :uid
AND ((skills.skill_ID = 1 AND skills.skill_level = ch_skills.skill1)
OR (skills.skill_ID = 2 AND skills.skill_level = ch_skills.skill2)
OR (skills.skill_ID = 3 AND skills.skill_level = ch_skills.skill3)
OR (skills.skill_ID = 4 AND skills.skill_level = ch_skills.skill4)
OR (skills.skill_ID = 5 AND skills.skill_level = ch_skills.skill5))
I'm having a problem at the moment where I have a column called rating in the links table and there is definitely values other than 0 within the column but 0 is the only value which is returned foreach link. When I do a simple get for that column it then shows all the other values but not when I do an SQL Join.
I know the problem is my joining of the tables but I'm unsure how I would go about joining these specific tables.
Database Table Structure
The rating column is the one which is causing me problems.
'links' id | title | url | user_id | list_id | rating | weight | date_created
'list' id | list_title | list_description | user_id | rating | views | date_created
'link_ratings' id | user_id | link_id | rated | date_created
Model:
public function get_latest(){
$this->db->limit(100);
$this->db->order_by('links.date_created', 'DESC');
$this->db->select('*');
$this->db->select('links.id as current_link_id');
$this->db->from('links');
$this->db->join('list', 'links.list_id = list.id');
$this->db->join('users', 'links.user_id = users.id');
$this->db->join('link_ratings', 'links.id = link_ratings.link_id','left');
$get_latest = $this->db->get();
return $get_latest;
}
Any Help is appreciated.
You should try this:
function get_latest(){
$this->db->select('list.*, users.*, links.id as current_link_id');
$this->db->from('links');
$this->db->join('list', 'links.list_id = list.id');
$this->db->join('users', 'links.user_id = users.id');
$this->db->join('link_ratings', 'links.id = link_ratings.link_id','left');
$this->db->order_by('links.date_created', 'DESC');
$this->db->limit(100);
$get_latest = $this->db->get()->result_array(); #fetch all rows here
echo "<pre>";print_r( $get_latest );die; #print all rows and see if its fetching ratings corrctly or not.
echo $this->db->last_query();die; #check the query generated
return $get_latest;
}
The reason will be purely logical, in that the join will be causing no results to be returned because there are no results. I've fallen into this many times.
I am not able to diagnose your particular problem but when faced with issues like this I:
1- turn on the CI profiler
2- var_dump the array so you can see what's going on
3- write a traditional SQL query and run it in PHPMyAdmin
One, or a combination of all three, will enable you to diagnose.
I need mysql code or php to handle some search query
Lets say we have these 5 items in our store.
ID | TYPE | Pattern
1. | Kilner | scissor
2. | Kilner | forcep
3. | Boyd | scissor Small
4. | Boyd | scissor large
5. | Boyd | forcep
6. | Boyd | clamp
Could you help me mysql query to handle below operation
If we search 'boyd' then numbers 3 4 5 and 6 should come up.
If we search 'scissor' then numbers 1 3 and 4 should come up.
If we search 'boyd scissor', numbers 3 and 4 should come up.
If they search' Kilner scissor' then only no 1 should display.
Let me know
thanks
the way to do it in mysql is full text search
SELECT *, MATCH(field) AGAINST ('word1 word2 word3') AS score
FROM table
WHERE MATCH(field) AGAINST('word1 word2 word3')
look this tutorial http://devzone.zend.com/26/using-mysql-full-text-searching/
try this query
SELECT * FROM `table` WHERE `name` LIKE '%$search_var%'
PDO structure
$db = $this->pdo->prepare("SELECT * FROM `table` WHERE `name` LIKE :mysearch");
$db->execute( array("mysearch"=>'%'.$mysearch.'%') );
The query you ask is a bit complex. You want to return matches in both columns, but if both columns match, then single matches have to be discarded.
This means, one way or another, run a query requiring two matches and one requiring one match, comparing the results and returning the appropriate set.
Performance-wise, I believe it is better to run one query that will fetch both, and then handle the results in PHP (you could handle them in MySQL through the use of a superquery).
So:
// We split keywords
$keywords = array_unique(preg_split('/\s+/', $search));
$inset = array();
foreach($keywords as $keyword)
$inset[] = "'".mysql_real_escape_string($keyword)."'";
$sql_in = '('.implode(',', $inset).')';
$query = "SELECT *, IF(type IN $sql_in, 1,0)+IF(pattern IN $sql_in,1,0) AS matches FROM mytable WHERE (type IN $sql_in) OR (pattern IN $sql_in) ORDER BY matches DESC;";
The above uses the discouraged mysql_ functions. Using PDO, that would be:
$keywords = array_unique(preg_split('/\s+/', $search));
// Generate a (?,?,?..?) template as long as $keywords
$sql_in = '('.implode(',', array_fill(0, count($keywords), '?')).')';
$query = "SELECT *, IF(type IN $sql_in, 1,0)+IF(pattern IN $sql_in,1,0) AS matches FROM mytable WHERE (type IN $sql_in) OR (pattern IN $sql_in) ORDER BY matches DESC;";
$st = $db->prepare($query);
$st->execute($keywords);
Note that the above uses exact match, so "Boyd" will retrieve a match with "Boyd", but "Boy" won't. Use the % matching character to change this behaviour.
Now we retrieve a table which is identical to MyTable but has one extra column, "matches", containing either 2 or 1. Can't contain 0 because of the WHERE limitation: one of the two matches must be true and count as 1.
The 2's will be returned first, so we can do
if (!isset($matches))
$matches = $tuple['matches'];
else
if ($tuple['matches'] < $matches)
break;
that is, we save the first (and highest) value, and only accept that value for the subsequent tuples. As soon as an inferior match comes by, we exit the loop and close the cursor.
This may be done in MySQL with
SELECT * FROM ( the above query ) AS newTable
WHERE matches = (
SELECT MAX(matches) FROM ( the above query ) AS tmpTable
);
but it incurs a performance penalty.
$search=array('byod','scissor');
$st=""; $st2="";
foreach($search as $value){$st.="type=%$value% or ";$st2.="pattern=%$value% or ";}
$st2=substr($st2,0,-3);
echo "select * from tablename where $st $st2";