an SQL query in LINQ - linq-to-sql

I have a table with these columns: CombinationID, IndexID, Value
There is a sql query:
SELECT CombinationID
FROM CombinationIndex
where IndexID <> 4
group by CombinationID
order by sum(case indexid when 1 then -Value else Value end) desc
How could I write this query in c# by linq?

I think this should just about do it for you (it's all off the top of my head so there could be slight syntactical errors):
var results = context
.CombinationIndexes
.Where(i => i.IndexID != 4)
.GroupBy(i => i.CombinationID)
.OrderBy(g => g.Sum(i => i.IndexID == 1 ? -i.Value : i.Value))
.Select(g => g.Key);

Related

How to perform GroupBy of a GroupBy in laravel?

I have a reports table which looks like something as follows:
Reports is monthly reports of users putting their efforts. It's many to many relationship table.
id
user_id
project_id
total_effort
created_at
1
5
232
40
2023-01-23
I want to get all users with their contributions projects-wise so that I can create an excel something like this.
I am able to group users by group and get their collective data, but unable to group by project id as well.
So far here is my query
$data = Report::select('user_id')
->selectRaw("SUM(total_effort) as total, DATE_FORMAT(report_for_date, '%b,%Y') new_date")
->groupBy('user_id')->with('userDetail:id,first_name,last_name')->get();
And this query return
[0] => Array
(
[user_id] => 2
[total] => 500
[new_date] => Dec,2022
[user_detail] => Array
(
[id] => 2
[first_name] => Hermione
[last_name] => Granger
)
)
But what I am actually looking for is something like this:
[0] => Array
(
[user_id] => 2
[total] => 500
[new_date] => Dec,2022
[projects]=>Array(
[0]=>Array(
[project_id]=>1,
[total]=>30,
[project_detail]=>Array(
[id]=>1
[name]=>Project 1
)
)
[1]=>Array(
[project_id]=>41,
[total]=>30,
[project_detail]=>Array(
[id]=>41
[name]=>Project 41
)
)
[2]=>Array(
[project_id]=>32,
[total]=>30,
[project_detail]=>Array(
[id]=>32
[name]=>Project 32
)
)
)
[user_detail] => Array
(
[id] => 2
[first_name] => Hermione
[last_name] => Granger
)
)
So that I can loop the data and plot them in excel.
How can this be done? Even if it is just a Raw MySQL query how to do Groupby inside a groupBy?
Some reference that I checked but without any help
sql group by sub group
Mysql Nested query and GROUP BY
using group function inside group function
You can use with() method to load the relation with groupby clause
$data = Report::select('user_id', 'project_id')
->selectRaw("SUM(total_effort) as total, DATE_FORMAT(report_for_date, '%b,%Y') new_date")
->groupBy('user_id')
->groupBy('project_id')
->with('userDetail:id,first_name,last_name')
->with('projectDetail:id,name')
->get();
I would query the active projects within the reporting period and then use that to build up the main query with conditional aggregation (pivot) -
// get list of projects within reporting period
$projects = DB::table('projects p')
->join('reports r', 'p.id', '=', 'r.project_id')
->select('p.id', 'p.name')
->whereBetween('r.created_at', ['2023-01-01', '2023-01-31'])
->groupBy('p.id')
->get();
// build conditional aggregates
$columns = ['CONCAT(u.first_name, \' \', u.last_name) AS username'];
foreach ($projects as $project) {
$columns[] = "SUM(IF(r.project_id = {$project->id}, total_effort, 0)) AS project_{$project->id}";
}
// Add total column
$columns[] = 'SUM(total_effort) AS total';
$report = DB::table('reports r')
->join('users u', 'r.user_id', '=', 'u.id')
->selectRaw(implode(',', $columns))
->whereBetween('r.created_at', ['2023-01-01', '2023-01-31'])
->groupBy('r.user_id')
->get();
The idea is to build and execute a query which looks something like this -
SELECT
CONCAT(u.first_name, ' ', u.last_name) AS username,
SUM(IF(r.project_id = 232, total_effort, 0)) AS project_232,
SUM(IF(r.project_id = 233, total_effort, 0)) AS project_233,
SUM(IF(r.project_id = 234, total_effort, 0)) AS project_234,
SUM(total_effort) AS total
FROM reports r
JOIN users u ON r.user_id = u.id
WHERE r.created_at BETWEEN '2023-01-01' AND '2023-01-31'
GROUP BY r.user_id

Yii 1.1 model relation can't use joined table column on select

This is my class
Class System extends CActiveRecord
{
public function relations() {
return array(
'SystemInverterModuleMountGrouped' => array(self::HAS_MANY, 'SystemInverterModule', array('id' => 'system_inverter_id'),
'through' => 'SystemInverter',
'group' => 'system_id, SystemInverterModuleMountGrouped.mount_id',
'condition' => 'SystemInverterModuleMountGrouped.mount_id is not null AND SystemInverterModuleMountGrouped.mount_id != "" AND number_of_mounts > 0 AND
CASE WHEN Mount.unit_of_measure = 1 THEN
SystemInverterModuleMountGrouped.existing_array != 1
ELSE true
END',
'select' => '*, '
. 'SUM(SystemInverterModuleMountGrouped.number_of_mounts) AS number_of_mounts_grouped, ',
'with' => 'Mount'
)
);
}
}
This is working fine, but now I want to sum number_of_mounts in a certain condition
array(
'select' => '*, '
. 'IF(Mount.unit_of_measure IN (1,2,3), 0, SUM(SystemInverterModuleMountGrouped.number_of_mounts)) AS number_of_mounts_grouped, ',
)
It doesn’t work and yii throws an error
Active record “SystemInverterModule” is trying to select an invalid column “IF(Mount.unit_of_measure IN (1”. Note, the column must exist in the table or be an expression with alias.
Notice that I’m able to use Mount.unit_of_measure on the condition
'condition' => 'CASE WHEN Mount.unit_of_measure = 1 THEN '
It works with raw sql query
SELECT IF(Mount.unit_of_measure IN (1,2,3), 0, SUM(SystemInverterModuleMountGrouped.number_of_mounts)) AS number_of_mounts_grouped
FROM `SystemInverterModules` `SystemInverterModuleMountGrouped`
LEFT OUTER JOIN `SystemInverter` `SystemInverter`
ON (`SystemInverter`.`id` = `SystemInverterModuleMountGrouped`.`system_inverter_id`)
LEFT OUTER JOIN `Inventory` `Mount`
ON (`SystemInverterModuleMountGrouped`.`mount_id` = `Mount`.`id`)
WHERE (SystemInverterModuleMountGrouped.mount_id is not null AND SystemInverterModuleMountGrouped.mount_id != "" AND
number_of_mounts > 0 AND
CASE WHEN Mount.unit_of_measure = 1 THEN
SystemInverterModuleMountGrouped.existing_array != 1
ELSE true END
)
AND (`SystemInverter`.`system_id` = '42146')
GROUP BY system_id, SystemInverterModuleMountGrouped.mount_id
ORDER BY sort_mounting ASC
You should use array for declaring select in this case - string format does not work well for complicated expressions:
'select' => [
'*',
'IF(Mount.unit_of_measure IN (1,2,3), 0, SUM(SystemInverterModuleMountGrouped.number_of_mounts)) AS number_of_mounts_grouped',
],

Subquery By Zend Database Format

I created a query in MYSQL as follows :
select subsql.item_id, subsql.uid, subsql.post_date, subsql.uid_prev,
max(workflow_trans.date) AS pre_date
from (
select item_id, max(date) AS post_date, uid, uid_prev
from workflow_trans
where uid = 'name' and date <= 'date1' and date >= 'date2'
group by item_id, uid, uid_prev
) AS subsql
left join workflow_trans on subsql.item_id = workflow_trans.item_id and
subsql.uid_prev = workflow_trans.uid and subsql.post_date > workflow_trans.date
where workflow_trans.date is not null
group by subsql.item_id, subsql.uid, subsql.post_date, subsql.uid_prev
order by subsql.post_date
The In translated it to Zend DB format as follows :
$this->db->select()->from(array("subsql" => $this->db->select()
->from(array($this->_name), array('item_id', 'max(date) AS post_date',
'uid', 'uid_prev'))
->where("uid = ?", $username)->where("date >= ?", $tgl1)
->where("date <= ?", $tgl2)
->group(array('item_id', 'uid', 'uid_prev'))),
array('subsql.item_id','subsql.uid',
'subsql.post_date','subsql.uid_prev','max(workflow_trans.date)
as pre_date'))
->joinLeft($this->_name, 'subsql.item_id = workflow_trans.item_id
and subsql.uid_prev = workflow_trans.uid and subsql.post_date >
workflow_trans.date')
->where("workflow_trans.date != ?", null)
->group(array('subsql.item_id', 'subsql.uid', 'subsql.post_date',
'subsql.uid_prev'))
->order(array('subsql.post_date'))
Yet the Zend model could not working. i've been reexamined it, and made 3 changes, but still there is something wrong with the formatting. Fresh pair of sharp eyes are appreciated.
ANSWER UPDATE
Hello guys, I already found it, below the running code :
$this->db->select()->from(array("subsql" => $this->db->select()
->from(array($this->_name), array('item_id', 'max(date) AS post_date',
'uid', 'uid_prev'))
->where("uid = ?", $username)->where("date >= ?", $tgl1)
->where("date <= ?", $tgl2)
->group(array('item_id', 'uid', 'uid_prev'))),
array('subsql.item_id','subsql.uid','subsql.post_date','subsql.uid_prev'))
->joinLeft(array($this->_name), 'subsql.item_id = workflow_trans.item_id and
subsql.uid_prev = workflow_trans.uid and
subsql.post_date > workflow_trans.date',
array('max(workflow_trans.date) as pre_date'))
->where("workflow_trans.date is not null")
->group(array('subsql.item_id', 'subsql.uid', 'subsql.post_date',
'subsql.uid_prev'))
->order(array('subsql.post_date'));
You should define the column from joining table in its own join function, and of course I got it wrong on how to handle the null.
If we talks about zf3, this query generates same sql as with yours.
$from = $this->getSql()->select('workflow_trans')
->columns(['item_id, max(date) AS post_date, uid, uid_prev', new Literal('max(workflow_trans.date) AS pre_date')])
->where(['uid = ?' => 'name'])
->where(['date <= ?' => 'date1'])
->where(['date >= ?' => 'date2'])
->group(['item_id', 'uid', 'uid_prev']);
$query = $this->getSql()->select()
->columns(['item_id, uid, post_date, uid_prev'])
->from(['subsql' => $from])
->join('workflow_trans', 'subsql.item_id = workflow_trans.item_id and subsql.uid_prev = workflow_trans.uid and subsql.post_date > workflow_trans.date', [])
->where(new IsNotNull('workflow_trans.date'))
->group(['subsql.item_id', 'subsql.uid', 'subsql.post_date', 'subsql.uid_prev'])
->order('subsql.post_date');

Count number of rows with distinct column

I'm trying to count the number of rows with a distinct column with Active Record.
The following SQL works and gives me the correct result:
SELECT COUNT(DISTINCT(user_id)) FROM attempts WHERE score = 100 AND problem_id = 1
But this code throws an ActiveRecord::StatementInvalid error:
attempts.where(:score => 100).count(:distinct => :user_id)
Try:
attempts.count('user_id', :conditions => "score = 100", :distinct => true)
more infos: http://ar.rubyonrails.org/classes/ActiveRecord/Calculations/ClassMethods.html

Sql (zend db select) of multiple selects

I need a bit of help.
I have (reference?) table with columns: id , user_id , key , value
It is pretty much a user profile table
and I would like to have SQL (I am using zend db table, but general SQL help will do) where I get "all 'user_id's where 'key' is somekey and 'value' is somevalue of that user_id but only if it also matches where 'key' is otherkey and 'value' is othervalue".
In other words I want to get users that have shoes of maker NIKE and color BLACK.
therefore 'key' is shoecolor and 'value' is BLACK and also another row with same user_id has 'key' is shoemaker and 'value' is NIKE.
This is what I could come up with, but doesn't work.
SELECT `user_profiles`.* FROM `user_profiles` WHERE
(`key` = 'shoecolor' AND `value` = 'BLACK') AND
(`key` = 'shoemaker' AND `value` = 'NIKE')
In case someone is knowledgable in zend db:
$where = array('shoecolor' => 'BLACK', 'shoemaker' => 'NIKE');
foreach ($where as $key => $value) {
$sql = $db->quoteInto('key = ?', $key);
$sql .= ' AND ' . $db->quoteInto('value = ?', $value);
$select->where($sql);
}
// make unique result
//$select->groupBy('user_id');
$resultSet = $zendTableInstance->fetchAll($select);
Please Help.
Thanx.
Because the key/value pair is in the row, your query is looking for a key that is 3 AND 4. No value can be 3 and 4 at the same time ;)
SELECT user_profiles.* FROM user_profiles WHERE (key = 3 AND value = 21) AND (key = 4 AND value = 55)
will not work.
You could do a join on yourself, and check for these values?
SELECT user_profiles.*
FROM user_profiles up1
JOIN user_profiles up2 ON up1.user_id = up2.user_id
WHERE
(up1.key = 3 AND up1.value = 21)
AND (up2.key = 4 AND up2.value = 55)