Convert SQL Query with Subquery to Laravel query - sql

Is it possible to convert my SQL Query to Laravel 4 Query
SQL:
SELECT
Branch_tbl.ID,
Branch_tbl.BranchName,
(
SELECT
SUM(Expenses.Expense)
FROM
Expenses
WHERE
Expenses.BranchID = Branch_tbl.ID
) as 'Total Expenses'
FROM
Branch_tbl

You may try raw expression (maybe it's not to best solution)
DB::table('branch_tbl')
->select(
'branch_tbl.id',
'branch_tbl.branchname',
DB::raw("
( select sum(expenses.expense) from expenses where
expenses.branchid = branch_tbl.id
)as 'total expenses'"))->get();
If you have a complex subquery you can separate it:
$subQuery = DB::table('expenses')
->select(DB::raw('sum(expenses.expense)'))
->whereRaw('expenses.branchid = branch_tbl.id');
DB::table('branch_tbl')
->select('branch_tbl.id','branch_tbl.branchname',
DB::raw("(" . $subQuery->toSql() . ") as 'total expenses'")
)
->get();
Be careful not to create any SQL injection with raw expression.

Related

Using WITH in MonetDB

I'm trying to execute the next query in MonetDB using "WITH":
with a as (select data_string from colombia.dim_tempo)
select
t.ano_mes
,f.sg_estado
,f.cod_produto
, sum(f.qtd_vendidas) as qtd_vendidas
, count(*) as fact_count
from colombia.fact_retail_market f, colombia.dim_tempo t
where f.cod_anomes = t.data_string
and t.data_string in (a.data_string)
group by
t.ano_mes
,f.sg_estado
,f.cod_produto ;
But always get this message:
What's wrong with the sentence?
The WHERE clause needs to be:
WHERE f.cod_anomes = t.data_string AND
t.data_string IN (SELECT data_string FROM a)
That is, IN needs to be followed by a subquery against the CTE.

SQL join statement between table and selection in Knex

I have SQL statement :
select from resources
left join ( select resource_id, sum(price) as PostScoreSum from
prices where '2019-06-8' < dateto and '2019-06-15' >
datefrom group by resource_id ) BB on
resources.resources_id = BB.resource_id")
Using Knex, I can write this statement as knex.raw('.....'), but after this knex statement I cannot used modify (to have chain of statements, knex.raw('...').modify...is not posible). Is it possible to write this join in Knex, between table and selection without using raw.
Not clear what actually your issue is but following will generate your above query-
const sql = knex('resources')
.leftJoin((query) => {
query
.columns([
'resource_id',
knex.raw('sum(price) as PostScoreSum')
])
.from('prices')
.where('dateto', '>', '2019-06-8')
.where('datefrom', '<', '2019-06-8')
.groupBy('resources_id')
.as('BB')
}, 'resources.resources_id', 'BB.resource_id')
.toSQL();
console.log(sql) ;

cannot group with eloquent with PostreSQL

Here's my Eloquent query:
$visits = Visit::orderBy('date', 'desc')->groupBy('user_id')->get(['date', 'user_id']);
But posgreSQL is refusing the query, telling me:
SQLSTATE[42803]: Grouping error: 7 ERROR: column "visits.date" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: select "date", "user_id" from "visits" group by...
the same stuff works on MySQL when I disable ONLY_FULLY_GROUP_BY
what can I do to make it work? It would be great if I didn't have to edit configs, just the code.
This selects the latest date for each user_id:
$sub = Visit::select('user_id', DB::raw('max("date") "date"'))->groupBy('user_id');
$sql = '(' . $sub->toSql() . ') as "sub"';
$visits = Visit::join(DB::raw($sql), function($join) {
$join->on('visits.user_id', 'sub.user_id')
->on('visits.date', 'sub.date');
})->orderBy('visits.date', 'desc')->get(['visits.date', 'visits.user_id']);
If there are multiple visits for a user_id and date combination, the query returns all of them. Removing the duplicates is possible, but makes the query more complex.
It's easier to remove them afterwards:
$visits = $visits->unique('user_id');
Using postgre sql you could use distinct on user_id and order your date column to pick latest date per user_id, In laravel you could raw expression
$visits = Visit::select(DB::raw('distinct on (user_id)'), 'date')
->orderBy('date', 'desc')
->get();
Demo

how do I join two tables sql

I have an issue that I'm hoping you can help me with. I am trying to create charting data for performance of an application that I am working on. The first step for me to perform two select statements with my feature turned off and on.
SELECT onSet.testName,
avg(onSet.elapsed) as avgOn,
0 as avgOff
FROM Results onSet
WHERE onSet.pll = 'On'
GROUP BY onSet.testName
union
SELECT offSet1.testName,
0 as avgOn,
avg(offSet1.elapsed) as avgOff
FROM Results offSet1
WHERE offSet1.pll = 'Off'
GROUP BY offSet1.testName
This gives me data that looks like this:
Add,0,11.4160277777777778
Add,11.413625,0
Delete,0,4.5245277777777778
Delete,4.0039861111111111,0
Evidently union is not the correct feature. Since the data needs to look like:
Add,11.413625,11.4160277777777778
Delete,4.0039861111111111,4.5245277777777778
I've been trying to get inner joins to work but I can't get the syntax to work.
Removing the union and trying to put this statement after the select statements also doesn't work. I evidently have the wrong syntax.
inner join xxx ON onSet.testName=offset1.testName
After getting the data to be like this I want to apply one last select statement that will subtract one column from another and give me the difference. So for me it's just one step at a time.
Thanks in advance.
-KAP
I think you can use a single query with conditional aggregation:
SELECT
testName,
AVG(CASE WHEN pll = 'On' THEN elapsed ELSE 0 END) AS avgOn,
AVG(CASE WHEN pll = 'Off' THEN elapsed ELSE 0 END) AS avgOff
FROM Results
GROUP BY testName
I just saw the filemaker tag and have no idea if this work there, but on MySQL I would try something along
SELECT testName, sum(if(pll = 'On',elapsed,0)) as sumOn,
sum(if(pll = 'On',1,0)) as numOn,
sum(if(pll ='Off',elapsed,0)) as sumOff,
sum(if(pll ='Off',1,0)) as numOff,
sumOn/numOn as avgOn,
sumOff/numOff as avgOff
FROM Results
WHERE pll = 'On' or pll='Off'
GROUP BY testName ;
If it works for you then this should be rather efficient as you do not need to join. If not, thumbs pressed that this triggers another idea.
The difficulty you have with the join you envisioned is that the filtering in the WHERE clause is performed after the join was completed. So, you would still not know what records to use to compute the averages. If the above is not implementable with FileMaker then check if nested queries work. You would then
SELECT testName, on.avg as avgOn, off.avg as avgOff
FROM ( SELECT ... FROM Results ...) as on, () as off
JOIN on.testName=off.testName
If that is also not possible then I would look for temporary tables.
OK guys... thanks for the help again. Here is the final answer. The statement below is FileMaker custom function that takes 4 arguments (platform, runID, model and user count. You can see the sql statement is specified. FileMaker executeSQL() function does not support nested select statements, does not support IF statements embedded in select statements (calc functions do of course) and finally does not support the SQL keyword VALUES. FileMaker does support the SQL keyword CASE which is a little more powerful but is a bit wordy. The select statement is in a variable named sql and result is placed in a variable named result. The ExecuteSQL() function works like a printf statement for param text so you can see the swaps do occur.
Let(
[
sql =
"SELECT testName, (sum( CASE WHEN PLL='On' THEN elapsed ELSE 0 END)) as sumOn,
sum( CASE WHEN PLL='On' THEN 1 ELSE 0 END) as countOn,
sum( CASE WHEN PLL='Off' THEN elapsed ELSE 0 END) as sumOff,
sum( CASE WHEN PLL='Off' THEN 1 ELSE 0 END) as countOff
FROM Results
WHERE Platform = ?
and RunID = ?
and Model = ?
and UserCnt = ?
GROUP BY testName";
result = ExecuteSQL ( sql ; "" ; ""
; platform
; runID
; model
; userCnt )
];
getAverages ( Result ; "" ; 2 )
)
For those interested the custom function looks like this:
getAverages( result, newList, pos )
Let (
[
curValues = Substitute( GetValue( data; pos ); ","; ¶ );
sumOn = GetValue( curValues; 2 ) ;
countOn = GetValue( curValues; 3 );
sumOff = GetValue( curValues; 4 );
countOff = GetValue( curValues; 5 );
avgOn = sumOn / countOn;
avgOff = sumOff / countOff
newItem = ((avgOff - avgOn) / avgOff ) * 100
];
newList & If ( pos > ValueCount( data); newList;
getAverages( data; If ( not IsEmpty( newList); ¶ ) & newItem; pos + 1 ))
)

Can any one help me to convert this sql query into ruby query

I am new to ruby and i am not able to convert the given query into ruby query, can any one help me for that
"SELECT * FROM domainurls WHERE domaindetail_id = ?",#domain.id ,"and count IN (SELECT Max( count ) FROM domainurls WHERE domaindetail_id =?",#domain.id")"
Here's one way to do it:
Domainurl.
where(:domaindetail_id => #domain.id).
where("count IN (SELECT MAX(count) FROM domainurls WHERE domaindetail_id = ? ", #domain.id)