Django queryset how to aggregate (ArrayAgg) over queryset with union? - django

from django.contrib.postgres.aggregates import ArrayAgg
t1= Table1.objects.values('id')
t2= Table2.objects.values('id')
t3= Table3.objects.values('id')
t = t1.union(t2, t3)
t.aggregate(id1=ArrayAgg('id'))
This raises error
{ProgramingError} column "__col1" does not exist
Equivalent raw SQL
SELECT array_agg(a.id) from
(
SELECT id FROM table1
UNION
SELECT id FROM table2
UNION
SELECT id FROM table3
) as a

The aggregate function try to find column __col1, but it doesn't exist. So explicitly name the columns with F() objects and use aggregate function:
t1= Table1.objects.values(__col1=F('id'))
t2= Table2.objects.values(__col1=F('id'))
t3= Table3.objects.values(__col1=F('id'))
t = t1.union(t2, t3)
t.aggregate(Avg('id'))

Related

How can I combine 2 different models with union?

I want to combine the results of the queries of two different models with union, but sql code parts are different, and Django throws an exception:
Unable to get repr for <class 'django.db.models.query.QuerySet'>
django.db.utils.ProgrammingError: UNION types numeric and character varying cannot be matched
LINE 1: ...order"."update_date", "core_filled"."status", "core_trig..
custom_qs = active_qs.annotate(**{'order_numberx': F('order_number'),
'condition_side': Value('GTE', output_field=CharField()),
}).values("order_number", "account_id",
"order_type", "price",
"buy_sell", "status",
"add_date", "update_date",
"status", "condition_side",
"total_price")
filled_qs = trigger_qs.annotate(**{'order_numberx': F('order_number'),
'total_price': Value(0, output_field=DecimalField())
}).values("order_number", "account_id",
"order_type", "price",
"buy_sell", "status",
"add_date", "update_date",
"status", "condition_side",
"total_price")
orders_qs = active_qs.union(trigger_qs)
SQL QUERY
(SELECT "core_custom"."order_number", "core_custom"."account_id", "core_custom"."order_type", "core_custom"."market_code", "core_custom"."channel_code", "core_custom"."price", "core_custom"."volume", "core_custom"."volume_executed", "core_custom"."buy_sell", "core_custom"."status", "core_custom"."add_date", "core_custom"."update_date", "core_custom"."client_id", "core_custom"."post_only", "core_custom"."status", "core_custom"."total_price", GTE AS "condition_side"
FROM "core_custom"
WHERE ("core_custom"."account_id" = 1549 AND "core_custom"."status" IN (N, P)))
UNION
(SELECT "core_filled"."order_number", "core_filled"."account_id", "core_filled"."order_type", "core_filled"."market_code", "core_filled"."channel_code", "core_filled"."price", "core_triggerorder"."volume", "core_filled"."volume_executed", "core_filled"."buy_sell", "core_filled"."status", "core_filled"."add_date", "core_filled"."update_date", "core_filled"."client_id", "core_filled"."post_only", "core_filled"."status", "core_filled"."condition_side", 0 AS "total_price"
FROM "core_filled"
WHERE ("core_triggerorder"."account_id" = 1549 AND "core_filled"."status" = N))
How can I control order of columns in sql query generated by ORM?

How to use RelBuilder.pivot() method for a query without an alias passed for Pivot expression values?

https://github.com/apache/calcite/blob/master/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
Here in RelBuilder class documentation for pivot() method provided example is below.
for SQL ::
SELECT * FROM (SELECT mgr, deptno, job, sal FROM emp) PIVOT (SUM(sal) AS ss, COUNT(*) AS c FOR (job, deptno) IN (('CLERK', 10) AS c10, ('MANAGER', 20) AS m20))
RelBuilder.pivot(groupKey, aggCalls, axes, valueMap.build().entrySet())
can be used to create a RelNode object. Here we pass a Map(alias, pivot_column_values) object as "values" parameter.
final Function<RelBuilder, RelNode> f = b -> b.scan("emp")
.pivot(b.groupKey("MGR"), Arrays.asList(b.sum(b.field("SAL")).as("SS"), b.count().as("C")),
b.fields(Arrays.asList("JOB", "DEPTNO")),
ImmutableMap.<String, List<RexNode>>builder()
.put("C10", Arrays.asList(b.literal("CLERK"), b.literal(10)))
.put("M20", Arrays.asList(b.literal("MANAGER"), b.literal(20))).build().entrySet())
.build();
How to pass "values" parameter when we don't have alias for pivot column values.
e.g. how to pass "values" parameter of RelBuilder.pivot() method for below query
SELECT * FROM (SELECT mgr, deptno, job, sal FROM emp) PIVOT (SUM(sal) AS ss, COUNT(*) AS c FOR (job, deptno) IN (('CLERK', 10), ('MANAGER', 20)))
Also is it compulsory to have at least one entry in values Map?

Get inserted uniqueidentifier from table B when its inserted from Table A insert trigger

I wasnt sure how to open the title but let me explain what is my problem.
I have two tables and both of them used uniqueidentifier as Id and they are auto generated by newsequentialid()
Now, when i make an insert to table B, it runes Insert trigger and i do some specific things inside this trigger and i also insert some values to another table called A and i need to retreive this table A's inserted Id but i am unable to find a solution.
Also let me explain why i need such a trigger. When a user creates an invoice with products in it where they have stock information, this trigger is responsible to create a stock transaction with header and detail about the products inserted (this stock detail table also has a trigger and it updates the warehouses) etc. etc.
i hope this gives some hint what i am trying to do
CREATE TRIGGER [dbo].[IT_TBLDebitInvoiceDetails] ON [dbo].[TBLDebitInvoiceDetails] AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
declare #cnt int;
--HEADER
declare #DocumentId uniqueidentifier;
declare #OrganizationId uniqueidentifier;
declare #Date date;
declare #TermDate date;
declare #DespatchDate date;
declare #DespatchNo nvarchar(20);
declare #WarehouseId uniqueidentifier;
declare #CustomerId uniqueidentifier;
declare #StockId uniqueidentifier;
declare #CurrencyTypeId uniqueidentifier;
declare #GrandTotal money;
--Auditable
declare #WhoCreated uniqueidentifier;
declare #DateCreated datetime;
declare #WhoUpdated uniqueidentifier;
declare #DateUpdated datetime;
--DETAIL
declare #ProductId uniqueidentifier;
declare #Quantity decimal(18, 2);
declare #ProductType int;
SELECT TOP(1) #OrganizationId = OrganizationId, #DocumentId = A.Id, #Date = A.[Date], #TermDate = A.TermDate, #DespatchDate = A.DespatchDate, #DespatchNo = A.DespatchNo,
#WarehouseId = A.WarehouseId, #CustomerId = A.CustomerId, #GrandTotal = A.GrandTotal,
#WhoCreated = A.WhoCreated, #DateCreated = A.DateCreated, #WhoUpdated = A.WhoUpdated, #DateUpdated = A.DateUpdated
FROM TBLDebitInvoices AS A
INNER JOIN inserted AS B ON A.Id = B.InvoiceId
/* CHECK STOCK TRANSACTION */
SELECT #cnt = COUNT(*) FROM inserted AS A
INNER JOIN TBLProducts AS B ON B.Id = A.ProductId
WHERE B.ProductType != 1
--we have products for stock, create stock header
IF(#cnt > 0)
BEGIN
INSERT INTO TBLStocks (OrganizationId, TransactionType, DocumentType, DocumentId, [Date], DeliveryDate, DeliveryNo, SourceWarehouseId, CustomerId, [Description], WhoCreated, DateCreated, WhoUpdated, DateUpdated, IsDeleted)
VALUES (#OrganizationId, 5, 0, #DocumentId, #Date, #DespatchDate, #DespatchNo, #WarehouseId, #CustomerId, '', #WhoCreated, #DateCreated, #WhoUpdated, #DateUpdated, 0);
SELECT #StockId = ???????;
END
INSERT INTO TBLStockDetails (StockId, ProductId, [Value])
SELECT #StockId, ProductId, SUM(Quantity) FROM (
SELECT A.ProductId AS ProductId, A.Quantity FROM inserted AS A
INNER JOIN TBLProducts AS B ON B.Id = A.ProductId
WHERE B.ProductType = 0
UNION ALL
SELECT C.IngredientID, A.Quantity * C.Quantity FROM inserted AS A
INNER JOIN TBLProducts AS B ON B.Id = A.ProductId
INNER JOIN TBLProductRecipes AS C ON C.ProductId = B.Id
WHERE B.ProductType = 2
) AS T1
GROUP BY ProductId;
UPDATE TBLDebitInvoices SET StockId = #StockId WHERE Id = #DocumentId;
/* CHECK DC TRANSACTION */
INSERT INTO TBLDebitCreditTransactions (TransactionType, DocumentType, DocumentId, PaymentStatus, [Date], Amount, AccountType, AccountId, CurrencyTypeId)
VALUES (1, 0, #DocumentId, 0, #TermDate, #GrandTotal, 0, #CustomerId, #CurrencyTypeId);
END
GO
inside this trigger i have this insert:
INSERT INTO TBLStocks (OrganizationId, TransactionType, DocumentType, DocumentId, [Date], DeliveryDate, DeliveryNo, SourceWarehouseId, CustomerId, [Description], WhoCreated, DateCreated, WhoUpdated, DateUpdated, IsDeleted)
VALUES (#OrganizationId, 5, 0, #DocumentId, #Date, #DespatchDate, #DespatchNo, #WarehouseId, #CustomerId, '', #WhoCreated, #DateCreated, #WhoUpdated, #DateUpdated, 0);
SELECT #StockId = ???????;
and i need the Id inserted to this table so i can use its id to insert its row elements.
it seems i found the answer, i wasnt sure inserted statement will give a separate result for the second insert, but it works
DECLARE #IdTable TABLE (StockId uniqueidentifier);
INSERT INTO TBLStocks (OrganizationId, TransactionType, DocumentType, DocumentId, [Date], DeliveryDate, DeliveryNo, SourceWarehouseId, CustomerId, [Description], WhoCreated, DateCreated, WhoUpdated, DateUpdated, IsDeleted)
OUTPUT Inserted.Id INTO #IdTable(StockId)
SELECT #OrganizationId, 5, 0, #DocumentId, #Date, #DespatchDate, #DespatchNo, #WarehouseId, #CustomerId, '', #WhoCreated, #DateCreated, #WhoUpdated, #DateUpdated, 0;
SELECT #StockId = StockId FROM #IdTable;
this will give the second table inserted uniqueidentifier

What is the wrong in this SAS AML Codes

proc sql noprint;
CREATE TABLE WORK.TRANS_SENT_TO_USA AS
SELECT DISTINCT T3.role_desc , T1.ACCOUNT_KEY , T1.TRANSACTION_KEY ,
T2.MOnth_key ,
T1.DATE_KEY as DAY ,
T1.CURRENCY_AMOUNT_IN_ACCOUNT_CCY as AMOUNT ,
T5.ACCOUNT_CURRENCY_CODE as currency ,
T6.FULL_NAME,
MAX(T4.BANK_NAME) as Ben_Bank
FROM DB_CORE.FSC_CASH_FLOW_FACT T1
INNER JOIN DB_CORE.FSC_DATE_DIM T2
ON T1.DATE_KEY = T2.DATE_KEY
INNER JOIN DB_CORE.FSC_CASH_FLOW_BANK_BRIDGE T3
ON T1.TRANSACTION_KEY = T3.TRANSACTION_KEY
INNER JOIN DB_CORE.FSC_BANK_DIM T4
ON T3.BANK_KEY = T4.BANK_KEY
INNER JOIN DB_CORE.FSC_ACCOUNT_DIM T5
ON T1.ACCOUNT_KEY = T5.ACCOUNT_KEY
INNER JOIN DB_CORE.FSC_EXT_PARTY_ACCOUNT_DIM T6
ON T1.BENEFICIARY_EXT_PARTY_KEY = T6.EXT_PARTY_ACCOUNT_KEY
WHERE T2.CALENDAR_DATE >= "&LAST_RUN_DATE"D
AND T3.ROLE_DESC like '%BENEFICIARY%'
AND T4.BANK_COUNTRY_CODE LIKE 'US%'
Group by T3.role_desc ,T1.ACCOUNT_KEY , T1.TRANSACTION_KEY ,
T2.MOnth_key ,
T1.DATE_KEY ,
T1.CURRENCY_AMOUNT_IN_ACCOUNT_CCY ,
T5.ACCOUNT_CURRENCY_CODE ;
RUN;
FULL_NAME is not in the GROUP BY. That should cause problems, but then again you didn't specifically describe your problem(s).

Raw query must include the primary key

I got a raw SQL statement in my views.py
Message.objects.raw('''
SELECT s1.ID, s1.CHARACTER_ID, MAX(s1.MESSAGE) MESSAGE, MAX(s1.c) occurrences
FROM
(SELECT ID, CHARACTER_ID, MESSAGE, COUNT(*) c
FROM tbl_message WHERE ts > DATE_SUB(NOW(), INTERVAL %s DAY) GROUP BY CHARACTER_ID,MESSAGE) s1
LEFT JOIN
(SELECT ID, CHARACTER_ID, MESSAGE, COUNT(*) c
FROM tbl_message WHERE ts > DATE_SUB(NOW(), INTERVAL %s DAY) GROUP BY CHARACTER_ID,MESSAGE) s2
ON s1.CHARACTER_ID=s2.CHARACTER_ID
AND s1.c < s2.c
WHERE s2.c IS NULL
GROUP BY CHARACTER_ID
ORDER BY occurrences DESC''', [days, days])
The result of this SQL statement (tested on database directly) is:
ID | CHARACTER_ID | MESSAGE | OCCURENCES
----+--------------+---------+--------------
148 | 10 | test | 133
But all I got is a InvalidQuery Exception with the information Raw query must include the primary key
Then I double checked the docs and read:
There is only one field that you can’t leave out - the primary key
field....An InvalidQuery exception will be raised if you forget to include the primary key.
As you can see I got the requested primary key added in my statement. What's wrong?
class Message(models.Model):
character = models.ForeignKey('Character')
message = models.TextField()
location = models.ForeignKey('Location')
ts = models.DateTimeField()
class Meta:
pass
def __unicode__(self):
return u'%s: %s...' % (self.character, self.message[0:20])
Include 1 as id to your query
Message.objects.raw('''
SELECT 1 as id , s1.ID, s1.CHARACTER_ID, MAX(s1.MESSAGE) MESSAGE, MAX(s1.c) occurrences
FROM
(SELECT ID, CHARACTER_ID, MESSAGE, COUNT(*) c
FROM tbl_message WHERE ts > DATE_SUB(NOW(), INTERVAL %s DAY) GROUP BY CHARACTER_ID,MESSAGE) s1
LEFT JOIN
(SELECT ID, CHARACTER_ID, MESSAGE, COUNT(*) c
FROM tbl_message WHERE ts > DATE_SUB(NOW(), INTERVAL %s DAY) GROUP BY CHARACTER_ID,MESSAGE) s2
ON s1.CHARACTER_ID=s2.CHARACTER_ID
AND s1.c < s2.c
WHERE s2.c IS NULL
GROUP BY CHARACTER_ID
ORDER BY occurrences DESC''', [days, days])
I reproduced the same problem using Python 2.7.5, Django 1.5.1 and Mysql 5.5.
I've saved the result of the raw call to the results variable, so I can check what columns it contains:
>>> results.columns
['ID', 'CHARACTER_ID', 'MESSAGE', 'occurrences']
ID is in uppercase, so in your query I changed s1.ID to s1.id and it works:
>>> results = Message.objects.raw('''
... SELECT s1.id, s1.CHARACTER_ID, MAX(s1.MESSAGE) MESSAGE, MAX(s1.c) occurrences
... FROM
... (SELECT ID, CHARACTER_ID, MESSAGE, COUNT(*) c
... FROM tbl_message WHERE ts > DATE_SUB(NOW(), INTERVAL %s DAY) GROUP BY CHARACTER_ID,MESSAGE) s1
... LEFT JOIN
... (SELECT ID, CHARACTER_ID, MESSAGE, COUNT(*) c
... FROM tbl_message WHERE ts > DATE_SUB(NOW(), INTERVAL %s DAY) GROUP BY CHARACTER_ID,MESSAGE) s2
... ON s1.CHARACTER_ID=s2.CHARACTER_ID
... AND s1.c < s2.c
... WHERE s2.c IS NULL
... GROUP BY CHARACTER_ID
... ORDER BY occurrences DESC''', [days, days])
>>> results.columns
['id', 'CHARACTER_ID', 'MESSAGE', 'occurrences']
>>> results[0]
<Message_Deferred_character_id_location_id_message_ts: Character object: hello...>
Make Sure the primary key is part of the select statement.
Example:
This will not work:
`Model.objects.raw("Select Min(id), rider_id from Table_Name group by rider_id")`
But this will work:
`Model.objects.raw("Select id, Min(id), rider_id from Table_Name group by rider_id")`
For those also stuck with this problem, perhaps like me, wondering why Django needs a pk, when you don’t have a pk for the query (eg you want multiple rows) – Django just needs an id field returned, the pk does not need to be part of a where clause. ie:
select * from table where foo = 'bar';
or
select id, description from table where foo = 'bar';
Both of these work, if there is a field id in the table. But this throws the error described by Thomas Schwärzl, because no id field is returned:
select description from table where foo = 'bar';