Laravel - Execute single query with multiple databases - laravel

I'm writing an archival function in a Laravel site and I can't figure out how to replicate this query using Laravel's query builder. My databases are 'archive' and 'live'.
INSERT INTO archive.daily_by_post
SELECT post_date, user_id, post_id
FROM live.clicks
WHERE timestamp BETWEEN '2014-07-28 00:00:00' AND '2014-07-28 23:59:59'
GROUP BY user_id, post_id;
Should I use a different method? Is this even possible?

It is possible of course.
However you need to build your query either using raw statement OR Connection::insert() mixed with Query\Builder like below:
$from = '2014-07-30 00:00:00';
$till = '2014-07-30 23:59:59';
$select = DB::table('live.clicks')
->select('post_date', 'user_id', 'post_id')
->whereBetween('updated_at', [$from, $till]) // empty array will do
->groupBy('user_id', 'post_id');
$statement = 'INSERT INTO archive.daily_by_post (specify fields if necessary) '
. $select->toSql();
DB::insert($statement, $select->getBindings());

Related

How to use WITH clause in Laravel Query Builder

I have SQL query (see example).
But I can't find a way how I can write it in Query Builder.
Do you have any ideas how is it possible?
WITH main AS (
SELECT id FROM table1
)
SELECT * FROM table2
WHERE
table2.id IN (SELECT * FROM main)
I want to get format like:
$latestPosts = DB::table('posts')
->select('user_id', DB::raw('MAX(created_at) as last_post_created_at'))
->where('is_published', true)
->groupBy('user_id');
$users = DB::table('users')
->joinSub($latestPosts, 'latest_posts', function ($join) {
$join->on('users.id', '=', 'latest_posts.user_id');
})->get();
but for WITH
Laravel has no native support for common table expressions.
I've created a package for it: https://github.com/staudenmeir/laravel-cte
You can use it like this:
$query = DB::table('table1')->select('id');
$result = DB::table('table2')
->withExpression('main', $query)
->whereIn('table2.id', DB::table('main')->select('id'))
->get();
Query builder has to be compatible with multiple database engines (mysql, postgresql, sql lite, sql server) and as such only offers support for common functionality.
Assuming your query returns data, you may be able to use the DB:select() method to execute a raw query.
$data = DB::select('WITH main AS (SELECT id FROM table1), SELECT * FROM table2 WHERE table2.id IN (SELECT * FROM main)');
The DB:select method also accepts a second parameter for using named bindings.
Alternatively there are packages available such as laravel-cte that will add the functionality to Eloquent/ Query Builder.

Converting a raw query to Laravel query builder

I have the following MySQL query which fetches a list of the last 9 authors to write a post and lists them in order of the date of the last post they wrote.
It's working properly but I'd like to re-write it using the Laravel Query Builder. Here is the query at the moment:
$authors = DB::select("
SELECT
`a`.`id`,
`a`.`name`,
`a`.`avatar`,
`a`.`slug` AS `author_slug`,
`p`.`subheading`,
`p`.`title`,
`p`.`slug` AS `post_slug`,
`p`.`summary`,
`p`.`published_at`
FROM
`authors` AS `a`
JOIN
`posts` AS `p`
ON `p`.`id` =
(
SELECT `p2`.`id`
FROM `posts` AS `p2`
WHERE `p2`.`author_id` = `a`.`id`
ORDER BY `p2`.`published_at` DESC
LIMIT 1
)
WHERE
`a`.`online` = 1
ORDER BY
`published_at` DESC
LIMIT 9
");
I understand the basics of using the query builder, but there doesn't appear to be anything in the Laravel docs that allows for me to JOIN a table ON a SELECT.
Can anyone suggest a way that I can write this query using the Laravel Query builder, or perhaps suggest a way that I can rewrite this query to make it easier to structure with the query builder?
Try to do like this
$data = DB::table('authors')
->select(
'a.id',
'a.name',
'a.avatar',
'a.slug AS author_slug',
'p.subheading',
'p.title',
'p.slug AS post_slug',
'p.summary',
p.published_at')
->from('authors AS a')
->join('posts AS p', 'p.id', '=', DB::raw("
(
SELECT p2.id FROM posts AS p2
WHERE p2.author_id = b.id
ORDER BY p2.published_at
DESC LIMIT 1
)"))
->where('a.online', 1)
->limit(9)
->orderBy('p.published_at', 'desc')
->get();

Eloquent query alternative

How can I write the following in Laravel's Eloquent?
SELECT *
FROM
( SELECT real_estate.property_id,
real_estate.amount_offered,
payee.summa
FROM real_estate
LEFT JOIN
(SELECT property_id,
SUM(amount) AS summa
FROM payments
GROUP BY property_id) payee ON payee.property_id = real_estate.property_id ) yoot
WHERE summa = 0.05 * amount_offered
Been on this for a while now and really can't get around it. Lemme explain the whole cause for the panic.
I have two tables, one for property and another for payments made on those properties. Now at any given time I will like to query for what properties have been paid for to a certain percentage hence the 0.05 which reps 5%. As it is the query works but I need an Eloquent alternative for it. Thanks
Anywhere you have subqueries in your SQL you'll need to use DB::raw with Eloquent. In this case you have a big subquery for the FROM statement, so the easiest way would be to do this:
DB::table(
DB::raw('SELECT real_estate.property_id, real_estate.amount_offered, payee.summa FROM real_estate LEFT JOIN (SELECT property_id, SUM(amount) AS summa FROM payments GROUP BY property_id) payee ON payee.property_id = real_estate.property_id)')
)
->where('summa', DB::raw('0.05 * amount_offered'))->get();
Notice I used DB::raw for the WHERE statment value as well. That's because you are doing a multiplication using a column name, and the value would otherwise be quoted as a string.
If you want to go a step further and build each subquery using Eloquent, then convert it to an SQL string and injecting it using DB::raw, you can do this:
$joinQuery = DB::table('payments')
->select('property_id', 'SUM(amount) AS summa')
->groupBy('property_id')
->toSql();
$tableQuery = DB::table('real_estate')
->select('real_estate.property_id', 'real_estate.amount_offered', 'payee.summa')
->leftJoin(DB::raw('(' . $joinQuery . ')'), function ($join)
{
$join->on('payee.property_id', '=', 'real_estate.property_id');
})
->toSql();
DB::table(DB::raw('(' . $tableQuery . ')'))->where('summa', DB::raw('0.05 * amount_offered'))->get();
In this case, the second approach doesn't have any benefits over the first, except perhaps that it's more readable. However, building subqueries using Eloquent, does have it's benefitfs when you'd need to bind any variable values to the query (such as conditions), because the query will be correctly built and escaped by Eloquent and you would not be prone to SQL injection.

Using Mysql WHERE IN clause in codeigniter

I have the following mysql query. Could you please tell me how to write the same query in Codeigniter's way ?
SELECT * FROM myTable
WHERE trans_id IN ( SELECT trans_id FROM myTable WHERE code='B')
AND code!='B'
You can use sub query way of codeigniter to do this for this purpose you will have to hack codeigniter. like this
Go to system/database/DB_active_rec.php
Remove public or protected keyword from these functions
public function _compile_select($select_override = FALSE)
public function _reset_select()
Now subquery writing in available
And now here is your query with active record
$this->db->select('trans_id');
$this->db->from('myTable');
$this->db->where('code','B');
$subQuery = $this->db->_compile_select();
$this->db->_reset_select();
// And now your main query
$this->db->select("*");
$this->db->where_in("$subQuery");
$this->db->where('code !=', 'B');
$this->db->get('myTable');
And the thing is done. Cheers!!!
Note : While using sub queries you must use
$this->db->from('myTable')
instead of
$this->db->get('myTable')
which runs the query.
Watch this too
How can I rewrite this SQL into CodeIgniter's Active Records?
Note : In Codeigntier 3 these functions are already public so you do not need to hack them.
$data = $this->db->get_where('columnname',array('code' => 'B'));
$this->db->where_in('columnname',$data);
$this->db->where('code !=','B');
$query = $this->db->get();
return $query->result_array();
Try this one:
$this->db->select("*");
$this->db->where_in("(SELECT trans_id FROM myTable WHERE code = 'B')");
$this->db->where('code !=', 'B');
$this->db->get('myTable');
Note: $this->db->select("*"); is optional when you are selecting all columns from table
try this:
return $this->db->query("
SELECT * FROM myTable
WHERE trans_id IN ( SELECT trans_id FROM myTable WHERE code='B')
AND code!='B'
")->result_array();
Is not active record but is codeigniter's way http://codeigniter.com/user_guide/database/examples.html
see Standard Query With Multiple Results (Array Version) section
you can use a simpler approach, while still using active record
$this->db->select("a.trans_id ,a.number, a.name, a.phone")
$this->db->from("Name_Of_Your_Table a");
$subQueryIn = "SELECT trans_id FROM Another_Table";
$this->db->where("a.trans_id in ($subQueryIn)",NULL);

Codeigniter select multiple rows?

How do I select multiple rows from SQL?
ie. $results->row(1,2,3,4,5,10)
Are you using ActiveRecord? If so, you can use the where_in() method when making your query. It's not something you do after the query is finished, as you seem to be doing in your example.
$this->db->where_in('id', array(1,2,3,4,5,10));
$query = $this->db->get('myTable');
// This produces the query SELECT * FROM `myTable` WHERE `id` IN (1,2,3,4,5,10)
See the this CodeIgniter docs section for more info on SELECT statement support.

Resources