group by in django aggregate function? - sql

I have problem writing group by sql into django app. Can any of you django users help me how to write this sql into django-friendly code? This is my model:
class Stock(models.Model):
name = models.CharField("Stock's name", max_length=200)
symbol = models.CharField("Stock's symbol", max_length=20)
class Dividend(models.Model):
amount = models.FloatField(default=0)
date = models.DateField('pay date')
stock = models.ForeignKey(Stock)
class UserStock(models.Model):
amount = models.FloatField('amount', default=0)
date = models.DateField('buy date')
price = models.FloatField('price', default=0)
user = models.ForeignKey(User)
stock = models.ForeignKey(Stock)
And this is sql code I want to write in django:
select stock_id, sum(price), sum(amount) as price from stocks_userstock group by stock_id;
I was trying to write something like this.
my_stock = UserStock.objects.filter(user=request.user)\
.annotate(sum_price = sum('price'), sum_amount = sum('amount'))
Thanks in advance, I hope it won't be a problem for some of you.

I believe just adding a values call will do that
my_stock = UserStock.objects.get(user=request.user)\
.values('stock_id').annotate(sum_price = sum('price'), sum_amount = sum('amount'))
and you will get back a list of dicts similar to
[
{'stock_id': 0, 'sum_price': 10, 'sum_amount': 25},
...
]
see here for more info

stock = Stock.objects.all().annotate(sum_price = Sum('user_stock__price'), sum_amount = Sum('user_stock__amount'))
It should work.
I've removed the User filter in my snippet to simplify but you can add it of course.

Related

Oracle error: Not a group by function

Select EVENTPLAN.PLANNO, EVENTPLANLINE.LINENO, RESOURCETBL.RESNAME,
COUNT(EVENTPLANLINE.NUMBERFLD) AS NUMBEROFRESOURCES,
LOCATION.LOCNAME, EVENTPLANLINE.TIMESTART, EVENTPLANLINE.TIMEEND
FROM EVENTPLAN, RESOURCETBL, EVENTPLANLINE, LOCATION, FACILITY
WHERE EVENTPLAN.PLANNO = EVENTPLANLINE.PLANNO
AND EVENTPLANLINE.RESNO = RESOURCETBL.RESNO
AND EVENTPLANLINE.LOCNO = LOCATION.LOCNO
AND FACILITY.FACNO = LOCATION.FACNO
AND FACILITY.FACNAME = 'Basketball arena'
AND EVENTPLAN.ACTIVITY = 'Operation'
AND EVENTPLAN.WORKDATE BETWEEN '1-OCT-13' AND '31-DEC-13'
GROUP BY EVENTPLAN.PLANNO, EVENTPLANLINE.LINENO,
RESOURCETBL.RESNAME,EVENTPLANLINE.NUMBERFLD;
On running this query I am getting an error: Not a group by function. Can someone please tell me why am I getting this error? I have added all the fields in the GROUP BY function.
When you use an aggregate function ALL scalar fields must be in GROUP BY function.
You have missed these:
LOCATION.LOCNAME, EVENTPLANLINE.TIMESTART, EVENTPLANLINE.TIMEEND
So, the right query will be:
SELECT
EVENTPLAN.PLANNO, EVENTPLANLINE.LINENO, RESOURCETBL.RESNAME,
COUNT(EVENTPLANLINE.NUMBERFLD) AS NUMBEROFRESOURCES,
LOCATION.LOCNAME, EVENTPLANLINE.TIMESTART, EVENTPLANLINE.TIMEEND
FROM EVENTPLAN, RESOURCETBL, EVENTPLANLINE, LOCATION, FACILITY
WHERE EVENTPLAN.PLANNO = EVENTPLANLINE.PLANNO
AND EVENTPLANLINE.RESNO = RESOURCETBL.RESNO
AND EVENTPLANLINE.LOCNO = LOCATION.LOCNO
AND FACILITY.FACNO = LOCATION.FACNO
AND FACILITY.FACNAME = 'Basketball arena'
AND EVENTPLAN.ACTIVITY = 'Operation'
AND EVENTPLAN.WORKDATE BETWEEN '1-OCT-13' AND '31-DEC-13'
GROUP BY EVENTPLAN.PLANNO, EVENTPLANLINE.LINENO, RESOURCETBL.RESNAME,
LOCATION.LOCNAME, EVENTPLANLINE.TIMESTART, EVENTPLANLINE.TIMEEND

ActiveRecord has_many with multiple conditions

I'm trying to find an object by checking for several of its relations.
Loan.joins(:credit_memo_attributes)
.where(credit_memo_attributes: {name: 'pr2_gtx1_y', value: '2014'})
.where(credit_memo_attributes: {name: 'pr1_gtx1_y', value: '2013'})
.where(credit_memo_attributes: {name: 'tx1_y', value: '2014'})
Calling to_sql on that gives:
"SELECT `loans`.* FROM `loans` INNER JOIN `credit_memo_attributes`
ON `credit_memo_attributes`.`loan_id` = `loans`.`id`
WHERE `credit_memo_attributes`.`name` = 'pr2_gtx1_y' AND `credit_memo_attributes`.`value` = '2014'
AND `credit_memo_attributes`.`name` = 'pr1_gtx1_y' AND `credit_memo_attributes`.`value` = '2013'
AND `credit_memo_attributes`.`name` = 'tx1_y' AND `credit_memo_attributes`.`value` = '2014'"
So, I'm checking for Loans that have credit_memo_attributes with all of those attributes. I know at least 1 of our 20,000 loans meets this criteria, but this query returns an empty set. If I only use 1 of the where clauses, it returns several, as I'd expect, but once I add even 1 more, it's empty.
Any idea where I'm going wrong?
Update:
Based on comments I believe you want multiple joins in your criteria. You can do that like this:
attr_1 = {name: 'pr2_gtx1_y', value: '2014'}
attr_2 = {name: 'pr1_gtx1_y', value: '2013'}
attr_3 = {name: 'tx1_y', value: '2014'}
Loan.something_cool(attr_1, attr_2, attr_3)
class Loan < ActiveRecord::Base
...
def self.something_cool(attr_1, attr_2, attr_3)
joins(sanitize_sql(["INNER JOIN credit_memo_attributes AS cma1 ON cma1.loan_id = loans.id AND cma1.name = :name AND cma1.value = :value", attr_1]))
.joins(sanitize_sql(["INNER JOIN credit_memo_attributes AS cma2 ON cma2.loan_id = loans.id AND cma2.name = :name AND cma2.value = :value", attr_2]))
.joins(sanitize_sql(["INNER JOIN credit_memo_attributes AS cma3 ON cma3.loan_id = loans.id AND cma3.name = :name AND cma3.value = :value", attr_3]))
end
If you look at the SQL generated (that you included in your question, thank you) you'll see that all those conditions are being ANDed together. There are NO rows for which name = 'pr2_gtx1_y' AND name = 'pr1_gtx1_y' (and so forth). So you are getting the result I would expect (no rows).
You can put all names and values into array like ids and years and pass those into where clause like this. Active Record will query all the values in the array.
Loan.joins(:credit_memo_attributes)
.where(credit_memo_attributes: {name: ids, value: years})
Personally I'm still learning active record, in this concern i don't think active record supports multiple where clauses.
Notice how the SQL version is returning your code: it is joining the requirements with an AND.
"SELECT `loans`.* FROM `loans` INNER JOIN `credit_memo_attributes`
ON `credit_memo_attributes`.`loan_id` = `loans`.`id`
WHERE `credit_memo_attributes`.`name` = 'pr2_gtx1_y' AND `credit_memo_attributes`.`value` = '2014'
AND `credit_memo_attributes`.`name` = 'pr1_gtx1_y' AND `credit_memo_attributes`.`value` = '2013'
AND `credit_memo_attributes`.`name` = 'tx1_y' AND `credit_memo_attributes`.`value` = '2014'"
Now, this is next to impossible. An Object.name can never be all pr2_gtx1_y, pr1_gtx1_y, and tx1_y. Same goes for the value attributes.
What you need here is an OR as opposed to the AND.
To this effect, try to change your query to the following:
Loan.joins(:credit_memo_attributes)
.where(
"credit_memo_attributes.name = ? and credit_memo_attributes.value = ?
OR credit_memo_attributes.names = ? and credit_memo_attributes.value = ?
OR credit_memo_attributes.name = ? and credit_memo_attributes.value = ?",
'pr2_gtx1_y', '2014',
'pr1_gtx1_y', '2013',
'tx1_y', '2014'
)

Convert SQL to LINQ with group by

I'm stumped trying to convert the following sql to linq:
SELECT t.* FROM(SELECT mwfieldid,MAX([TimeStamp]) AS MaxValue, BatchDocumentID
FROM mw_BatchField
GROUP BY mwfieldid,BatchDocumentID) x
JOIN mw_BatchField t ON x.mwfieldid = t.mwfieldid
AND x.MaxValue = t.TimeStamp
and x.BatchDocumentID = t.BatchDocumentID
So far I had to convert it to a stored proc to get it to work. I'd rather know how to write this correctly in linq. I tried using a sql to linq converter (http://www.sqltolinq.com/) which produced this code that had errors in it: (Are these converters any good? It didn't seem to produce anything useful with a few tries.)
From x In (
(From mw_BatchFields In db.mw_BatchFields
Group mw_BatchFields By
mw_BatchFields.MWFieldID,
mw_BatchFields.BatchDocumentID
Into g = Group
Select
MWFieldID,
MaxValue = CType(g.Max(Function(p) p.TimeStamp),DateTime?),
BatchDocumentID)
)
Join t In db.mw_BatchFields
On New With { .MWFieldID = CInt(x.MWFieldID), .MaxValue = CDate(x.MaxValue), .BatchDocumentID = CInt(x.BatchDocumentID) }
Equals New With { .MWFieldID = t.MWFieldID, .MaxValue = t.TimeStamp, .BatchDocumentID = t.BatchDocumentID }
Select
BatchFieldID = t.BatchFieldID,
BatchDocumentID = t.BatchDocumentID,
MWFieldID = t.MWFieldID,
TimeStamp = t.TimeStamp,
value = t.value,
DictionaryValue = t.DictionaryValue,
AutoFilled = t.AutoFilled,
employeeID = t.employeeID
Seems like a lot of code for such a simple query, and it doesn't compile.
So for every combination of mwfieldid and BatchDocumentID you want all columns of the row with the highest TimeStamp? This is something which is much easier to express in LINQ than SQL so I'm not surprised that an automated converter is making a meal of it.
You should be able to do:
Mw_BatchFields.GroupBy(x => new { x.Mwfieldid, x.BatchDocumentId })
.SelectMany(x => x.Where(y => y.TimeStamp == x.Max(z => z.TimeStamp)))
This (like your SQL) will return multiple rows per grouping key if there is more than one row in the group that shares the same maximum TimeStamp. If you only want row per key, you could use:
Mw_BatchFields.GroupBy(x => new { x.Mwfieldid, x.BatchDocumentId })
.Select(x => x.OrderByDescending(y => y.TimeStamp).First())
Edit:
Sorry, just twigged that you're working in VB, not C#, so not quite what you were looking for, but if you can live with the lambda syntax style, I think the above can be translated as:
Mw_BatchFields.GroupBy(Function(x) New With {x.Mwfieldid, x.BatchDocumentId}).Select(Function(x) x.OrderByDescending(Function(y) y.TimeStamp).First())
and:
Mw_BatchFields.GroupBy(Function(x) New With {x.Mwfieldid, x.BatchDocumentId}).SelectMany(Function(x) x.Where(Function(y) y.TimeStamp = x.Max(Function(z) z.TimeStamp)))

How i can get active product details from magento database?

I need a list of ACTIVE products from the magento database with the following information.
If there are additional information that is fine, but the following information need to be there.
SKU:
PRODUCT NAME:
PRODUCT CATEGORY:
SHORT DESCRIPTION:
LONG DESCRIPTION:
WEIGHT:
What is the way to write a query for this. I just need to get the data. No php, just sql query.(Db structure is bit complex)
try that, it works to get the product data: (status = 2 = product disabled, status = 1 = product enabled)
SELECT `e`.*, IF(_table_status.value_id > 0, _table_status.value, _table_status_default.value) AS `status
FROM `mage_catalog_product_entity` AS `e`
INNER JOIN `mage_catalog_product_entity_int` AS `_table_status_default`
ON (`_table_status_default`.`entity_id` = `e`.`entity_id`)
AND (`_table_status_default`.`attribute_id` = '80')
AND `_table_status_default`.`store_id` = 0
LEFT JOIN `mage_catalog_product_entity_int` AS `_table_status`
ON (`_table_status`.`entity_id` = `e`.`entity_id`)
AND (`_table_status`.`attribute_id` = (SELECT attribute_id FROM mage_eav_attribute WHERE attribute_code = 'status' AND entity_type_id = 4))
AND (`_table_status`.`store_id` = '1')
WHERE (IF(_table_status.value_id > 0, _table_status.value, _table_status_default.value) = '2')
For the category you will need some extra work. I get this sql query by doing the following in PHP and the Magento collection:
/* #var $productCollection Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection */
$productCollection = Mage::getModel('catalog/product')->getCollection();
$productCollection->addFieldToFilter('status', array('eq' => '2'))->load(true);

Converting SQL Query to Linq Lambda statement

I am trying to convert the the following SQL statement into a linq query but for some reason I cannot get it to work!!
SELECT o.ITEMID, COUNT(o.ITEMID) AS COUNT, MAX(i.QUANTITY) AS Quantity
FROM ORDERS AS o LEFT OUTER JOIN
INVENTORY AS i ON o.ITEMID = i.ITEMID
GROUP BY o.ITEMID
I found this link, somebody having a similar problem but I cant seem to apply this to what i need.
thanks for all your help.
This is the code i have so far
Dim castleavailability = _
From o In orders _
From i In inventorys _
Where (x >= o.ITEMID = i.ITEMID)
Group New With {o, i} By o.ITEMID Into oi()
Select New With {.ItemId = oi.Key, .Count = oi.Select(y >= y.o.ItemId).Count(), .Quantity = oi.Select(y >= y.i.Quantity).Max()}
the error I am getting now is "Definition of method 'oi' is not accessible in this context." referring to the "group new with" line. Any ideas on how to resolve this
Many Thanks
This should work for you
var query = from o in context.Orders
from i in context.Inventory
.Where(x = > o.ItemId = x.ItemId)
.DefaultIfEmpty()
group new { o, i } by o.ItemId into oi
select new
{
ItemId = oi.Key,
Count = oi.Select(y => y.o.ItemId).Count(),
Quantity = oi.Select(y => y.i.Quantity).Max(),
};
You can also use Linqer software to convert sql query to Linq Lambda query.
You can get this software from following link:
http://www.sqltolinq.com/