Store the result of sql and process it in informix - informix

We have a view which contains 2 columns: pattern_start_time, pattern_end_time.
The select query in the function will convert it to minutes and using that result we are processing to get the shift unused coverage.The function is getting created but the processing is not happening and getting the below error:
SQLError[IX000]:Routine (my_list) cant be resolved.
Also please enter image description heresuggest to loop till the length of the result.
CREATE function myshifttesting(orgid int) returning int;
DEFINE my_list LIST( INTEGER not null );
DEFINE my_list1 LIST( INTEGER not null );
define i, j, sub, sub1 int;
define total int;
TRACE ON;
TRACE 'my testing starts';
INSERT INTO TABLE( my_list )
select
((extend(current, year to second) + (dots.v_shift_coverage.pattern_start_time - datetime(00:00) hour to minute) - current)::interval minute(9) to minute)::char(10)::INTEGER
from
dots.v_shift_coverage
where
org_guid = orgid;
INSERT INTO TABLE( my_list1 )
select
((extend(current, year to second) + (dots.v_shift_coverage.pattern_end_time - datetime(00:00) hour to minute) - current)::interval minute(9) to minute)::char(10)::INTEGER
from
dots.v_shift_coverage
where
org_guid = orgid;
let sub = 0;
let sub1 = 0;
let total = 0;
for j = 0 to 4
if (my_list(j) < my_list1(j))
then
if (my_list(j + 1) > my_list1(j))
then
let sub = sub + my_list(j + 1) - my_list1(j);
end if;
end if;
end for
if (my_list(0) > my_list1(4))
then
let sub1 = my_list(0) - my_list1(4);
end if;
let total = sub + sub1;
return total;
end function;

The error that you are receiving is because my_list(j) is not valid Informix syntax to access a LIST element. Informix is interpreting my_list(j) as a call to a function named mylist.
You can use a temporary table to "emulate" an array with your logic, something like this:
CREATE TABLE somedata
(
letter1 CHAR( 2 ),
letter2 CHAR( 2 )
);
INSERT INTO somedata VALUES ( 'a1', 'a2' );
INSERT INTO somedata VALUES ( 'b1', 'b2' );
INSERT INTO somedata VALUES ( 'c1', 'c2' );
INSERT INTO somedata VALUES ( 'd1', 'd2' );
INSERT INTO somedata VALUES ( 'e1', 'e2' );
DROP FUNCTION IF EXISTS forloop;
CREATE FUNCTION forloop()
RETURNING CHAR( 2 ) AS letter1, CHAR( 2 ) AS letter2;
DEFINE number_of_rows INTEGER;
DEFINE iterator INTEGER;
DEFINE my_letter1 CHAR( 2 );
DEFINE my_letter2 CHAR( 2 );
-- Drop temp table if it already exists in the session
DROP TABLE IF EXISTS tmp_data;
CREATE TEMP TABLE tmp_data
(
tmp_id SERIAL,
tmp_letter1 CHAR( 2 ),
tmp_letter2 CHAR( 2 )
);
-- Insert rows into the temp table, serial column will be the access key
INSERT INTO tmp_data
SELECT 0,
d.letter1,
d.letter2
FROM somedata AS d
ORDER BY d.letter1;
-- Get total rows of temp table
SELECT COUNT( * )
INTO number_of_rows
FROM tmp_data;
FOR iterator = 1 TO number_of_rows
SELECT d.tmp_letter1
INTO my_letter1
FROM tmp_data AS d
WHERE d.tmp_id = iterator;
-- Check if not going "out of range"
IF iterator < number_of_rows THEN
SELECT d.tmp_letter2
INTO my_letter2
FROM tmp_data AS d
WHERE d.tmp_id = iterator + 1;
ELSE
-- iterator + 1 is "out of range", return to the beginning
SELECT d.tmp_letter2
INTO my_letter2
FROM tmp_data AS d
WHERE d.tmp_id = 1;
END IF;
RETURN my_letter1, my_letter2 WITH RESUME;
END FOR;
END FUNCTION;
-- Running the function
EXECUTE FUNCTION forloop();
-- Results
letter1 letter2
a1 b2
b1 c2
c1 d2
d1 e2
e1 a2
5 row(s) retrieved.

Related

Processing aborted due to error Snowflake

I've encountered this error:
Execution error in stored procedure: SQL execution internal error: Processing aborted due to error at Snowflake.execute
when running this script:
CREATE OR REPLACE PROCEDURE DATES_TABLE (INITIALDATE VARCHAR, FINALDATE VARCHAR)
RETURNS VARCHAR
LANGUAGE JAVASCRIPT
EXECUTE AS CALLER
AS
$$
var DATESDIFF = (Date.parse(formatDate(FINALDATE)) - Date.parse(formatDate(INITIALDATE)))/ (1000 * 3600 * 24);
snowflake.execute(
{
sqlText: ` CREATE OR REPLACE TEMPORARY TABLE TEMP_DATE_RANGE AS SELECT DATE FROM (
SELECT
CAST(DATEADD (DAY, DatesDiff.n, :1) AS DATE) AS DATE
FROM (
SELECT
ROW_NUMBER() OVER (ORDER BY 1) - 1
FROM
TABLE (generator (rowcount => :3))) DatesDiff (n)
); `,
binds: [formatDate(INITIALDATE), formatDate(FINALDATE), DATESDIFF]
}
);
function formatDate(date) {
var d = new Date(date),
month = '' + (d.getMonth() + 1),
day = '' + d.getDate(),
year = d.getFullYear();
if (month.length < 2)
month = '0' + month;
if (day.length < 2)
day = '0' + day;
return [year, month, day].join('-');
}
$$
;
CALL DATES_TABLE('2021-04-01','2021-05-24');
Which when ran outside of the stored procedure, creates a table with dates between the range inputted.
Any idea why this is happening, how to sort it out?
The problem is in binding a variable to TABLE (generator (rowcount => :3)), as Snowflake expects a constant there.
Instead, you could do something like:
SELECT ROW_NUMBER() OVER (ORDER BY 1) - 1 AS rn
FROM TABLE (generator (rowcount => 1000))
QUALIFY rn < :2
I did some cleanup, and this works:
CREATE OR REPLACE PROCEDURE DATES_TABLE (INITIALDATE VARCHAR, FINALDATE VARCHAR)
RETURNS VARCHAR
LANGUAGE JAVASCRIPT
EXECUTE AS CALLER
AS
$$
var DATESDIFF = (Date.parse(formatDate(FINALDATE)) - Date.parse(formatDate(INITIALDATE)))/ (1000 * 3600 * 24);
snowflake.execute(
{
sqlText: `
CREATE OR REPLACE TEMPORARY TABLE TEMP_DATE_RANGE AS
SELECT CAST(DATEADD(DAY, DatesDiff.rn, :1) AS DATE) AS DATE
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY 1) - 1 AS rn
FROM TABLE (generator (rowcount => 1000))
QUALIFY rn < :2
)
;`
, binds: [formatDate(INITIALDATE), DATESDIFF]
}
);
function formatDate(date) {
var d = new Date(date),
month = '' + (d.getMonth() + 1),
day = '' + d.getDate(),
year = d.getFullYear();
if (month.length < 2)
month = '0' + month;
if (day.length < 2)
day = '0' + day;
return [year, month, day].join('-');
}
$$
;
CALL DATES_TABLE('2021-04-01','2021-05-24');
select * from TEMP_DATE_RANGE;
For a shorter way of generating a sequence of dates, see my answer to https://stackoverflow.com/a/66449068/132438.

Remove a object from a table listed inside a different table

So i have 2 tables
local table1 = {1,2,3,4,5,6,7,8,9}
local table2 = {2,4,6,8}
I want remove the number in table 2 from table 1, to then use table one with the numbers removed in more code. How would i go about doing this?
When you read the data into the table, set the value of the index of whatever you are reading in as the key in the table. This avoids collisions and allows easy comparisons against another table.
local table1 = {}
local table2 = {}
-- read in your values as keys into the two tables
-- just an example I have no idea how you are populating the tables but hope it helps
table1 = {['input1'] = 0, ['input6'] = 0, ['input3'] = 0}
table2 = {['input1'] = 0, ['input3'] = 0}
newTable = {}
function tableHasKey(table, key)
return table[key] ~= nil
end
for key, _ in pairs(table1) do
if not tableHasKey(table2, key) then
table.insert(newTable, key)
end
end
for _, value in pairs(newTable) do
print(value)
end
The result is 'input6' when I run this. Which means all values not in table2 that are in table1 are now in newTable. If the values are unique between tables it's easier to compare keys than values. The final result is an indexed table where the result is stored in the value of the hash object.
#! /usr/bin/env lua
local table1 = {1,2,3,4,5,6,7,8,9}
local table2 = {2,4,6,8}
for number = 1, #table1 do
for delete = 1, #table2 do
if table1[number] == table2[delete] then
for i = number, #table1 -1 do
table1[i] = table1[i +1]
end -- shuffle every entry in table down
table1 [#table1] = nil -- erase last entry
end -- number == delete
end -- loop through table2
end -- loop through table1
for i = 1, #table1 do print( table1[i] ) end
1
3
5
7
9
The other answers listed here seem correct, but they seem a little too aggressive on memory or time complexity. Here's my take on a filter function optimized for lists of numbers.
-- t1 : table, the original set of values
-- t2 : table, the set of values to remove from t1
-- returns : table, a subset of elements from t1 not found in t2
local function filter(t1, t2)
-- Assumptions :
-- 1) t1 and t2 are arrays, not dictionaries
-- 2) t1 and t2 do not have mixed indices or mixed values
-- 3) t1 and t2 are sorted
assert(type(t1) == "table", "t1 expected to be a table")
assert(type(t2) == "table", "t2 expected to be a table")
assert(type(next(t1)) == "number" or type(next(t1)) == "nil", "t1 expected to be an array")
assert(type(next(t2)) == "number" or type(next(t2)) == "nil", "t2 expected to be an array")
-- Early Outs :
if #t1 == 0 then
return {}
elseif #t2 == 0 then
return t1
end
-- step through each list and compare each index as you go
local filteredT = {}
local i = 1
local j = 1
local sizeT1 = #t1
local sizeT2 = #t2
while (i <= sizeT1) and (j <= sizeT2) do
if t1[i] == t2[j] then
-- found a match, exclude from output
i = i + 1
j = j + 1
elseif t1[i] < t2[j] then
-- no match, add elements from t1
table.insert(filteredT, t1[i])
i = i + 1
else -- t1[i] > t2[j]
-- no match, ignore elements from t2
j = j + 1
end
end
-- we've made it to the end of one of the lists, add the rest of t1
for i = i, sizeT1, 1 do
table.insert(filteredT, t1[i])
end
return filteredT
end
This solution doesn't have unnecessary loop iterations and a number of early outs for optimization.
local a = {1,2,3,4,5,6,7,8,9}
local b = {2,4,6,8}
local result1 = filter(a, b)
print(table.concat(result1, ", ")) -- 1, 3, 5, 7, 9
local c = {"a", "b", "c", "d"}
local d = {"c", "d"}
local result2 = filter(c, d)
print(table.concat(result2, ", ")) -- "a", "b"

How to have sum function of a field of MB and GB values in MVC

My field values are like:
810.9 MB
1.2 GB
395.1 MB
982.3 MB
7.7 GB
149.4 MB
10.0 GB
429.1 MB
3.1 GB
and I want to sum this column in gb in my ASP.NET MVC controller.
But I have no idea how to do this.
You could try something like this:
-- This is your "raw" input - just all the strings in your example
DECLARE #input TABLE (Measure VARCHAR(50))
INSERT INTO #input ( Measure )
VALUES ('810.9 MB'), ('1.2 GB'), ( '395.1 MB'), ( '982.3 MB'), ( '7.7 GB'), ( '149.4 MB'), ( '10.0 GB'), ( '429.1 MB'), ( '3.1 GB')
-- Now declare a separate table that contains (1) the raw value, (2) the contained *numerical* value, and (3) the unit of measure
DECLARE #Storage TABLE (Measure VARCHAR(50), NumValue DECIMAL(20,4), Unit VARCHAR(10))
-- Fill your raw input into that "working table"
INSERT INTO #Storage (Measure, NumValue, Unit)
SELECT
Measure,
NumMeasure = CAST(SUBSTRING(Measure, 1, CHARINDEX(' ', Measure)) AS DECIMAL(20, 2)),
Unit = SUBSTRING(Measure, CHARINDEX(' ', Measure) + 1, 9999)
FROM
#input
SELECT * FROM #Storage
-- when you select from that "working" table, you can now easily *SUM* the numerical values,
-- and show them on screen whichever way you want - as "xxx MB" or "yyyy GB" or whatever - up to you
SELECT
SUM(CASE Unit
WHEN 'MB' THEN NumValue * 1000000
WHEN 'GB' THEN NumValue * 1000000000
ELSE NumValue
END),
CAST(SUM(CASE Unit
WHEN 'MB' THEN NumValue * 1000000
WHEN 'GB' THEN NumValue * 1000000000
ELSE NumValue
END) / 1000000000.0 AS VARCHAR(25)) + ' GB'
FROM
#Storage
Update:
If you want to do this in C# code, try this:
foreach(var item in list)
{
// split "item" into two parts
string[] parts = item.Split(' ');
// parts[0] should be a decimal value
decimal numValue = 0.0m;
if (decimal.TryParse(parts[0], out numValue))
{
decimal convertedValue = 0.0m;
if(parts[1] == "MB")
{
convertedValue = numValue * 1000000;
}
else if (parts[1] == "GB")
{
convertedValue = numValue * 1000000000;
}
}
}

How to use a numeric parameter in a stored procedure?

Good morning,
I'm having troubles to integrate a working query into a stored procedure.
My main issue, is that I'm using a WHILE loop with an integer, and that the stored procedure is having troubles with it.
My working query/code is the following:
CREATE TABLE #tempScaffStandingByTime
(
TotalStanding INT,
MonthsAgo INTEGER
)
DECLARE #StartDate DATETIME = null
DECLARE #months INTEGER = 12
use [Safetrak-BradyTechUK]
WHILE #months >= 0
BEGIN
SET #StartDate = DATEADD(mm, -12 + #months, DATEADD(mm, 0, DATEADD(mm,
DATEDIFF(mm,0,GETDATE()-1), 1)))
INSERT INTO #tempScaffStandingByTime
select TOP 1 COUNT(*) OVER () AS TotalRecords, #months
from asset a
join wshhistory h on h.assetid = a.uid
where a.deleted = 0 and h.assetstate <> 6
AND (dbo.getdecommissiondate(a.uid) > #StartDate)
group by a.uid
SET #months -= 3
END
SELECT * FROM #tempScaffStandingByTime
DROP TABLE #tempScaffStandingByTime
This results in the input which I want:
I then tried to import this code into my stored procedure
DECLARE #Query varchar (8000)
, #Account varchar (100) = 'BradyTechUK'
SET #Account = 'USE [Safetrak-' + #Account + ']'
/************************************************************************************/
/********** Create Table to hold data ***********************************************/
CREATE TABLE #tempScaffStandingByTime
(
TotalStanding INT,
MonthsAgo INTEGER
)
/************************************************************************************/
/********** Populate temp table with data *******************************************/
DECLARE #StartDate DATETIME = null
DECLARE #months INTEGER = 12
SET #Query= +#Account+ '
WHILE '+#months+' >= 0
BEGIN
SET '+#StartDate+' = DATEADD(mm, -12 + ('+#months+', DATEADD(mm, 0, DATEADD(mm, DATEDIFF(mm,0,GETDATE()-1), 1)))
INSERT INTO #tempScaffStandingByTime
select TOP 1 COUNT(*) OVER () AS TotalRecords, '+#months+'
from asset a
join wshhistory h on h.assetid = a.uid
where a.deleted = 0 and h.assetstate <> 6
AND (dbo.getdecommissiondate(a.uid) > '+#StartDate+')
group by a.uid
SET '+#months+' -= 3
END'
EXEC (#Query)
/************************************************************************************/
/********** Select Statement to return data to sp ***********************************/
Select TotalStanding
, MonthsAgo
FROM #tempScaffStandingByTime
/************************************************************************************/
DROP TABLE #tempScaffStandingByTime
But when loading the stored procedure in SSRS I get a conversion error.
I can convert my parameter to a string, but then it won't count anymore.
I searched far and wide on the internet, tried various things, but can't get it to work.
Any help is appreciated, thanks!
It looks like your problem original comes from the lack of conversion between the INT in #months and your VARCHAR in #Accounts and #Query.
You need to cast the months to a string to append it, otherwise the SQL Server thinks you're trying to do addition.
However you'll also have problems with the usage of your #StartDate variable as you try to set it via your dynamic SQL which is not going to work like that - and as with #months it'll have an incorrect datatype, but I'm also unsure why it's written as is, and what you're tying to achieve with it
I think - from what you're writing - that this might be what you're looking for?
SET #Query= #Account + '
DECLARE #StartDate DATETIME = null
DECLARE #months VARCHAR(2) = ''12''
WHILE #months >= 0
BEGIN
SET #StartDate = DATEADD(mm, -12 + #months, DATEADD(mm, 0, DATEADD(mm, DATEDIFF(mm,0,GETDATE()-1), 1)))
INSERT INTO #tempScaffStandingByTime
select TOP 1 COUNT(*) OVER () AS TotalRecords, #months, #StartDate
from asset a
join wshhistory h on h.assetid = a.uid
where a.deleted = 0 and h.assetstate <> 6
AND (dbo.getdecommissiondate(a.uid) > #StartDate)
group by a.uid
SET #months -= 3
END'
EXEC (#Query)

Passing comma separated value as an IN parameter in stored procedure

I am new to DB2 queries.
Here, I am passing a comma separated value as an IN parameter in a Stored Procedure. I want to search on the basis of those values.
Select * from USER where user_id in (IN_User);
Here, IN_User will have values of the kind ('val1','val2','val3')
It should return all the rows which has val1 or val2 or val3 as the User_id. As much as I know this can be done using UDF but I want to know is there any other way to do it without UDF.
please create a function to split the comma separated string
Please see the below function
CREATE FUNCTION StringToRows(
cString1 CLOB (10 M) ,
cStringSplitting1 VARCHAR(10) )
RETURNS TABLE (Lines VARCHAR(500))
SPECIFIC StringToRows_Big
DETERMINISTIC
NO EXTERNAL ACTION
CONTAINS SQL
BEGIN ATOMIC
DECLARE cStringSplitting VARCHAR(10);
DECLARE LenSplit SMALLINT;
SET cStringSplitting = cStringSplitting1;
SET LenSplit = LENGTH(cStringSplitting);
IF LENGTH(TRIM(cStringSplitting)) = 0 THEN
SET cStringSplitting = ' ', LenSplit = 1 ;
END IF ;
RETURN WITH
TEMP1 ( STRING) as (values (cString1) ),
TEMP2 ( Lines, STRING_left) as
(SELECT
SUBSTR(STRING,1, CASE WHEN LOCATE(cStringSplitting, STRING) = 0 THEN LENGTH(STRING) ELSE LOCATE(cStringSplitting,STRING) - 1 END),
(CASE WHEN (LOCATE(cStringSplitting, STRING) = 0) THEN '' ELSE SUBSTR(STRING, LOCATE(cStringSplitting,STRING) + LenSplit) END)
FROM TEMP1 WHERE LENGTH(STRING) > 0
UNION ALL
SELECT
SUBSTR(STRING_left,1, CASE LOCATE(cStringSplitting,STRING_left) WHEN 0 THEN LENGTH(STRING_left) ELSE LOCATE(cStringSplitting,STRING_left) - 1 END),
(CASE WHEN LOCATE(cStringSplitting,STRING_left) = 0 THEN '' ELSE SUBSTR(STRING_left, LOCATE(cStringSplitting,STRING_left) + LenSplit) END)
FROM TEMP2 WHERE LENGTH(STRING_left) > 0 )
SELECT Lines FROM TEMP2;
END
please see the sample stored procedure to call the function
CREATE PROCEDURE TEST_USR(IN #inputParam CLOB (10 M))
SPECIFIC TEST_USR
DYNAMIC RESULT SETS 1
P1: BEGIN
DECLARE CURSOR1 CURSOR WITH RETURN FOR
Select * from USER where user_id IN (SELECT * FROM TABLE(StringToRows(#inputParam, ',')) AS test);
OPEN CURSOR1;
END P1

Resources