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

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?

Related

combine column in json format in big query

I have columns in bigquery like this:
expected output:
I am trying to merge columns into json using bigquery.
I am taking letter before underscore(common name ) as column then converting.
I am trying this query:
with selectdata as (
SELECT a_firstname, a_middlename,a_lastname FROM `account_id.Dataset.Table_name`
)
select TO_JSON_STRING(t) AS json_data FROM selectdata AS t;
How can I join columns with condition or with case to achieve this output in bigquery
Consider below approach
create temp function extract_keys(input string) returns array<string> language js as """
return Object.keys(JSON.parse(input));
""";
create temp function extract_values(input string) returns array<string> language js as """
return Object.values(JSON.parse(input));
""";
select * except(row_id) from (
select format('%t',t) row_id,
split(key, '_')[offset(0)] as col,
'{' || string_agg(format('"%s":"%s"', split(key, '_')[safe_offset(1)], value)) || '}' as value
from your_table t, unnest(extract_keys(to_json_string(t))) key with offset
join unnest(extract_values(to_json_string(t))) value with offset
using(offset)
group by row_id, col
)
pivot (any_value(value) for col in ('a','b','c'))
if applied to sample data in your question - output is

Custom Function Power Query (M) - Return Table

I need a custom function that takes two parameters, Column1 and Column2, so:
For each Row, return the value of Column1 but only if exists a Value in the Column2 else return null
I have tried this:
let ColumnsFilter = (Tabla,C1,C2)=>
Table.AddColumn(Tabla, "Custom", each if [C2] <> null then [C1] else null)
in
ColumnsFilter
And calling the function:
#"Previous Step" = .....
#"P" = ColumnsFilter(#"Previous Step","Column1","Column2")
in
P
And is not working. clearly I am not using the syntax properly.
In summary I need a table as input and a table as output adding custom columns.
How can I write this?
(Please don't tell me to use the assisted of Power Query, I need to write similar functions manually)
Since you're passing column names as text and individual rows are a record type, you have to use Record.Field to pull the right column (field) from the current row (record).
let
ColumnsFilter = (Tabla as table, C1 as text, C2 as text) as table =>
Table.AddColumn(Tabla, "Custom",
each if Record.Field(_, C2) <> null then Record.Field(_, C1) else null
)
in
ColumnsFilter

How to use string as column name in Bigquery

There is a scenario where I receive a string to the bigquery function and need to use it as a column name.
here is the function
CREATE OR REPLACE FUNCTION METADATA.GET_VALUE(column STRING, row_number int64) AS (
(SELECT column from WORK.temp WHERE rownumber = row_number)
);
When I call this function as select METADATA.GET_VALUE("TXCAMP10",149); I get the value as TXCAMP10 so we can say that it is processed as SELECT "TXCAMP10" from WORK.temp WHERE rownumber = 149 but I need it as SELECT TXCAMP10 from WORK.temp WHERE rownumber = 149 which will return some value from temp table lets suppose the value as A
so ultimately I need value A instead of column name i.e. TXCAMP10.
I tried using execute immediate like execute immediate("SELECT" || column || "from WORK.temp WHERE rownumber =" ||row_number) from this stack overflow post to resolve this issue but turns out I can't use it in a function.
How do I achieve required result?
I don't think you can achieve this result with the help of UDF in standard SQL in BigQuery.
But it is possible to do this with stored procedures in BigQuery and EXECUTE IMMEDIATE statement. Consider this code, which simulates the situation you have:
create or replace table d1.temp(
c1 int64,
c2 int64
);
insert into d1.temp values (1, 1), (2, 2);
create or replace procedure d1.GET_VALUE(column STRING, row_number int64, out result int64)
BEGIN
EXECUTE IMMEDIATE 'SELECT ' || column || ' from d1.temp where c2 = ?' into result using row_number;
END;
BEGIN
DECLARE result_c1 INT64;
call d1.GET_VALUE("c1", 1, result_c1);
select result_c1;
END;
After some research and trial-error methods, I used this workaround to solve this issue. It may not be the best solution when you have too many columns but it surely works.
CREATE OR REPLACE FUNCTION METADATA.GET_VALUE(column STRING, row_number int64) AS (
(SELECT case
when column_name = 'a' then a
when column_name = 'b' then b
when column_name = 'c' then c
when column_name = 'd' then d
when column_name = 'e' then e
end from WORK.temp WHERE rownumber = row_number)
);
And this gives the required results.
Point to note: the number of columns you use in the case statement should be of the same datatype else it won't work

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

sqlite: How to get the column id of the selected column?

Given:
an sqlite database with a table T
the table T contains 10 columns - C0, C1 ... C9.
an sqlite3_stmt pointer corresponding to select C3,C2 from T
OK, so I can fetch the selected column values using the sqlite3_column_XXX family of methods (http://www.sqlite.org/capi3ref.html#sqlite3_column_blob), like this:
sqlite3_stmt *s;
sqlite3_prepare_v2(db, query, sizeof(query), &s, NULL);
while ((result = sqlite3_step(s)) == SQLITE_ROW)
{
const char *v3 = reinterpret_cast<const char *>(sqlite3_column_text(s, 0);
const char *v2 = reinterpret_cast<const char *>(sqlite3_column_text(s, 1);
}
What I need is the real index of the selected columns, i.e. 3 for v3 and 2 for v2.
Motivation: I want to be able to parse the returned string value into the real column type. Indeed, my schema says that c3 is a datetime, which sqlite treats as TEXT. So, sqlite3_column_type(s, 0) returns SQLITE3_TEXT, but the table metadata (available from pragma table_info(T)) retains the string datetime, which is the intended type of the column. Knowing it, I can parse the returned string into the respective unix time since the epoch, for instance.
But how can I map the query column index to the table column index:
query column 0 -> table column 3
query column 1 -> table column 2
Thanks.
You could use the sqlite C function sqlite3_column_decltype to get the declared column data type from the result stmt? It doesn't specifically answer your question (getting the original column's index), but could be an alternative way to achieve what you need?