Calling Bigquery Stored Procedure from Google Data studio - google-bigquery

Any idea how to call bigquery stored proc from Google data studio? I've a recursive query requirement which I've accomplished using Bigquery procedure. However need to pass parameters to this procedure from datastudio report and get results for the same and display in Data studio report. I have tried calling the procedure from Custom Query in Data studio no luck. Datastudio throws error. I tried calling procedure from a function however it doesn't work. ANy idea? How do I do I call procedure from Google Data studio?
Procedure that is written
DECLARE stop INT64 DEFAULT 30;
DECLARE v_target string;
DECLARE v_target_column_name string;
DECLARE max_counter INT64;
DECLARE min_counter INT64;
DECLARE v_exists bool;
SET v_target = 'v_target';
SET v_target_column_name = 'v_target_col';
create or replace table test.poc_sttm_resp as
select ROW_NUMBER() OVER() as counter,'N' as flag,source,source_column_name,target,target_column_name from test.test_sttm where target = v_target and target_column_name = v_target_column_name;
LOOP
SET max_counter = (select max(counter) from test.poc_sttm_resp);
SET min_counter = (select min(counter) from test.poc_sttm_resp where flag = 'N');
SET v_exists = EXISTS(select s.source from test.test_sttm s inner join
(select source,source_column_name from test.poc_sttm_resp where counter = min_counter
) r
on s.target = r.source and
s.target_column_name = r.source_column_name);
IF stop = 0 OR min_counter is null THEN
LEAVE;
END IF;
IF v_exists then
insert into test.poc_sttm_resp
select ROW_NUMBER() OVER() + max_counter as counter,'N' as flag,s.source,s.source_column_name,target,target_column_name from test.test_sttm s inner join
(select source,source_column_name from test.poc_sttm_resp where counter = (select min(counter) from test.poc_sttm_resp where flag = 'N')) r
on s.target = r.source and
s.target_column_name = r.source_column_name;
END IF;
update test.poc_sttm_resp set flag = 'Y' where counter = min_counter;
SET stop = stop - 1;
END LOOP;
I tried calling the procedure from Data Studio,
call functions.testproc(); which didn't work

Have you try make the connection between Google Data Studio and BigQuery using the community connectors?
Using the community connectors you can trigger a stored procedure with parameters.

Double check you connected correctly
You need to create/add the parameter in the data source or inside Data Studio via add parameter
In a data source
1. Sign in to Data Studio.
2. Edit your data source.
3. In the upper right, click ADD A PARAMETER.
4. You can also create a parameter while editing a report by selecting a component, then in the bottom right, clicking ADD A PARAMETER. Be sure to select a component based on the desired data source.
5. Configure the parameter's options and default value (see below).
Also, scrolling down on the page, you will see an example on how to do this with a sample calculation.

Related

Stored procedure for writing back to db2 database

Im new to db2 stored procedure, im approaching here for some help/guidance.
I have users who access cognos for reporting.
Recently I got a requirement from one of our clients for writing back to the db2 table based on user provided comment or input through IBM cognos.
I tried below code in db2 and cognos, but it works half way.
The catch is whenever a user provides a fresh entry it gets stored quickly but whenever a user tries to update the same entry, it takes almost 15-20 mins to refresh that record at table level. I won't understand what i can improve on my code here.
create procedure ngetl.new_update_comment (
in #p_job_status_summary_key integer
,in #p_comment varchar(4000)
,in #p_modified_by varchar(25)
)
dynamic result sets 1
begin
declare e1 cursor with return for
select 1
from ngetl.job_status_summary
where job_status_summary_key = 17076
with ur;
if upper(#p_modified_by) like '%IBM%'
or upper(#p_modified_by) like 'V%' then
update ngetl.job_status_summary
set ibm_comment = #p_comment
,modified_by_ibm = #p_modified_by
,timestamp_ibm = current_timestamp
where job_status_summary_key = #p_job_status_summary_key;
else update ngetl.job_status_summary
set sbi_comment = #p_comment
,modified_by_sbi = #p_modified_by
where job_status_summary_key = #p_job_status_summary_key;
end if;
commit;
open e1;
end

Does Creating Variable when it is needed will help in performance?

Will creating Variable whenever needed in Stored Procedure or Function or Trigger helps in performance optimization?
Which one is better of below or both have same performance?
Option 1:
CREATE TRIGGER [dbo].[UpdateAmount] ON [RequestDB].[dbo].[Invoice]
AFTER UPDATE
AS
BEGIN
IF UPDATE(Service_Amount)
BEGIN
DECLARE #NewService_Amount float,#OldService_Amount float //Var Created When needed
SELECT #NewService_Amount = I.Service_Amount FROM INSERTED I
SELECT #OldService_Amount = D.Service_Amount FROM DELETED D
IF (#NewService_Amount <> #OldService_Amount)
BEGIN
SELECT #InvId = I.Id FROM INSERTED I
DECLARE #DiffService_Amount float //Var Created When needed
SET #DiffService_Amount = #NewService_Amount - #OldService_Amount
UPDATE [RequestDB].[dbo].[Request] SET Actual_Amount = #DiffService_Amount WHERE Invoice_Id = #InvId
END
END
END
Option 2:
CREATE TRIGGER [dbo].[UpdateAmount] ON [RequestDB].[dbo].[Invoice]
AFTER UPDATE
AS
BEGIN
DECLARE #NewService_Amount float,#OldService_Amount float.#DiffService_Amount float //All Var Created at once on top of code
IF UPDATE(Service_Amount)
BEGIN
SELECT #NewService_Amount = I.Service_Amount FROM INSERTED I /*For New UPDATE Value: INSERTED. For Old BEFORE UPDATE Valie: DELETED*/
SELECT #OldService_Amount = D.Service_Amount FROM DELETED D
IF (#NewService_Amount <> #OldService_Amount)
BEGIN
SELECT #InvId = I.Id FROM INSERTED I
SET #DiffService_Amount = #NewService_Amount - #OldService_Amount
UPDATE [RequestDB].[dbo].[Request] SET Actual_Amount = #DiffService_Amount WHERE Invoice_Id = #InvId
END
END
END
The docs don't get too specific about variables other than to say that once it's declared it's available through that batch process:
The scope of a variable lasts from the point it is declared until the end of the batch or stored procedure in which it is declared.
My assumption would be declaring it later is better (given how they word the docs)--if you don't use it, avoid declaring it. However, the real answer would be to test it and profile it. Whichever works better in practice would be the real solution, IMHO.
I also hope this isn't a premature optimization. If you're down to declaration order to make your scripts run faster, you're probably looking in the wrong spot.

Cursor says its read only even though I declared it "for update"

I am trying to update a row inside a cursor. What I am trying to do is update a chain of records with OLD_QTY and NEW_QTY. However when I try to do my update it gives the error The cursor is READ ONLY even though I included for update of OLD_QTY, NEW_QTY in my declration. It makes no difference if I include OLD_QTY and NEW_QTY in the select statement.
declare #current_inv_guid uniqueidentifier
declare #last_inv_guid uniqueidentifier
declare #current_vid int
declare #last_vid int
--declare #current_new_qty money
declare #last_new_qty money
--declare #current_old_qty money
declare iaCursor cursor
for select INV_GUID, old_VID
--, OLD_QTY, NEW_QTY
from #IA
order by INV_GUID, old_vid, ENTRY_NUM
for update --of OLD_QTY, NEW_QTY
open iaCursor
Fetch next from iaCursor into #current_inv_guid, #current_vid --, #current_old_qty, #current_new_qty
while ##fetch_status = 0
begin
--test to see if we hit a new chain.
if(#last_inv_guid <> #current_inv_guid or #current_vid <> #last_vid)
begin
set #last_new_QTY = (select #lots.QTY_RECEIVED from #lots where #lots.INV_GUID = #current_inv_guid and LOT_VID = #current_vid)
set #last_inv_guid = #current_inv_guid
set #last_vid = #current_vid
end
--update the current link in the chain
update #ia
set OLD_QTY = #last_new_QTY,
NEW_QTY = #last_new_QTY + QTY_CHANGE,
#last_new_QTY = #last_new_QTY + QTY_CHANGE
where current of iaCursor
--get the next link
fetch next from iaCursor into #current_inv_guid, #current_vid --, #current_old_qty, #current_new_qty
end
close iaCursor
deallocate iaCursor
Putting a order by in the select made the cursor read only.
You are not explicitly saying what behaviour you want, therefore, default rules apply, according to which, the cursor may or may not be updatable, depending on the underlying query.
It's perfectly fine to use order by in an updatable cursor, but you have to be more verbose and tell SQL Server what you want in details, for instance:
declare iaCursor cursor
local
forward_only
keyset
scroll_locks
for
select INV_GUID, old_VID
from #IA
order by INV_GUID, old_vid, ENTRY_NUM
for update of OLD_QTY, NEW_QTY
There's an import but subtle note on the documentation page that Patrick listed:
If the query references at least one table without a unique index, the
keyset cursor is converted to a static cursor.
And of course STATIC cursors are read-only.
Besides the reason you mentioned in your answer, what you're attmepting to do runs counter to the way SQL is meant to be used. Try to update the data in sets, not by rows.
I'm not positive, as I don't know your table design, but I believe the following should work. You may get better performance out of this. In particular, I'm assuming that QTY_CHANGE is coming from #ia, although this may not be the case.
UPDATE #ia as a set (OLD_QTY, NEW_QTY) = (SELECT #lots.QTY_RECEIVED + (COUNT(b.*) * a.QTY_CHANGE),
#lots.QTY_RECEIVED + ((COUNT(b.*) + 1) * a.QTY_CHANGE)
FROM #lots
LEFT JOIN #ia as b
ON b.INV_GUID = a.INV_GUID
AND b.OLD_VID = a.OLD_VID
AND b.ENTRY_NUM < a.ENTRY_NUM
WHERE #lots.INV_GUID = a.INV_GUID
AND #lots.LOT_VID = a.OLD_VID)
WHERE EXISTS (SELECT '1'
FROM #lots
WHERE #lots.INV_GUID = a.INV_GUID
AND #lots.LOT_VID = a.OLD_VID)
EDIT:
... the previous version of the answer was written with a DB2 perspective, although it would otherwise be db-agnostic. It also had the problem of using the same value of QTY_CHANGE for every row, which is unlikely. This should be a more idiomatic SQL Server 2008 version, as well as being more likely to output the correct answer:
WITH RT AS (SELECT #IA.inv_guid, #IA.old_vid, #IA.entry_num,
COALESCE(MAX(#Lots.qty_received), 0) +
SUM(#IA.qty_change) OVER(PARTITION BY #IA.inv_guid, #IA.old_vid
ORDER BY #IA.entry_num)
AS running_total
FROM #IA
LEFT JOIN #Lots
ON #Lots.inv_guid = #IA.inv_guid
AND #Lots.lot_vid = #IA.old_vid)
UPDATE #IA
SET #IA.old_qty = RT.running_total - #IA.qty_change, #IA.new_qty = RT.running_total
FROM #IA
JOIN RT
ON RT.inv_guid = #IA.inv_guid
AND RT.old_vid = #IA.old_vid
AND RT.entry_num = #IA.entry_num
Some cursor declarations do not allow updates. The documentation gives a hint in the following remark:
If the SELECT statement does not support updates (insufficient permissions, accessing remote tables that do not support updates, and
so on), the cursor is READ_ONLY.
I ran into the same issue when trying to join the "inserted" object of a trigger in the select statement of the cursor declaration.
Use the DYNAMIC clause, found in documentation.
Defines a cursor that reflects all data changes made to the rows in its result set as you scroll around the cursor. The data values, order, and membership of the rows can change on each fetch.

Passing parameters from ReportViewer through to stored procedure data source for SSRS report

I have a report I am developing in BIDS for SSRS 2008 R2 that uses a stored procedure as its data source. I have set up parameters in the report and the report is passing them on to the stored procedure and everything works fine. However, I now need to convert the report so it gets its parameters passed to it from a ReportViewer control in a C# ASP.Net application instead of allowing them to be entered in the SSRS interface. I think I am fine on the C# side (using ServerReport.SetParameters), but I don't know what to do in BIDS to route those passed-in parameter values to the stored procedure. Can anyone provide an example?
I also need to prevent the report from displaying the UI for entering the parameters. Should I set the parameters to Hidden or Internal?
I would set the report parameters as Internal but read up on this article http://msdn.microsoft.com/en-us/library/aa337234.aspx for the section Hidden and Internal Parameters and decided for yourself what is appropriate to the problem.
Assuming you have a stored proc like
CREATE PROCEDURE dbo.RepeatAfterMe
(
#inputText varchar(50)
, #repeatFactor int = 10
)
AS
BEGIN
SET NOCOUNT ON
DECLARE #count int
DECLARE #hack TABLE (inputText varchar(50))
SET #count = 0
WHILE #count < #repeatFactor
BEGIN
INSERT INTO #hack SELECT #inputText
SET #count = #count + 1
END
SELECT H.* FROM #hack H
END
GO
Define 2 report parameters in SSRS (InputText as string, RepeatFactor as integer). Then, in your SSRS, your dataset would be defined like
EXECUTE dbo.RepeatAfterMe #inputText,
#repeatFactor
And then on the Parameters tab of the dataset, it would look like
#inputText =Parameters!InputText.Value
#repeatFactor =Parameters!RepeatFactor.Value
For completeness of solution, this is an approximation of the code I use to pass parameters in to a report control with an ID of rvReportViewer
Microsoft.Reporting.WebForms.ReportParameter[] reportParameters = null;
reportParameters = new Microsoft.Reporting.WebForms.ReportParameter[2];
reportParameters[0] = new Microsoft.Reporting.WebForms.ReportParameter("inputText", txtInput);
reportParameters[1] = new Microsoft.Reporting.WebForms.ReportParameter("repeatFactor", 10);
try
{
rvReportViewer.ServerReport.SetParameters(reportParameters);
}
catch(Microsoft.Reporting.WebForms.ReportServerException ex)
{
Response.Redirect("~/Error.aspx");
}

MySQL stored procedure - Problem outputting values

DROP PROCEDURE `uuu`//
CREATE DEFINER=`auth_tracker`#`%` PROCEDURE `uuu`()
BEGIN
DECLARE a,b CHAR(50);
DECLARE _output TEXT DEFAULT '';
DECLARE cur1 CURSOR FOR SELECT attribute_name, value
FROM user_product_attribute upa, product_attribute pa
WHERE upa.user_product_id IN
( SELECT upa.user_product_id
FROM user_product_attribute upa, user_product up, product_attribute pa, product p
WHERE pa.attribute_name = 'username'
AND pa.product_attribute_id = upa.product_attribute_id
AND pa.product_id = p.product_id
AND up.status = 'active'
AND p.product_name = 'broadband'
AND upa.value = 'lsolway-dsl' )
AND upa.product_attribute_id = pa.product_attribute_id;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO a, b;
SET _output = CONCAT(_output,a,b);
END LOOP;
SELECT _output;
END//
Hi guys, I am trying to get the SP to set the following output.. I cant see where i am going wrong.. Nothing is being returned..
The Query itself works fine standalone..
You're not defining any output parameters as far as I can tell. That would make it very difficult to get data back from a SQL stored procedure.
DECLARE an OUT param and stuff the value into that for output.
Also one suggestion, its always good to use # for your local variables in stored procedures. such as #_output, #a and #b.
The subquery is the reason.. I am only using one cursor for a query that would need two.. Im not even sure subqueries are possible in an SP..