I'm creating a bigquery procedure to collect data from an array through a function that contains the Array
This is the function:
CREATE OR REPLACE FUNCTION MY_DATASET.MY_FUNCTION() AS (
(
select [
['DATA1','DATA1PARAM1'],
['DATA2','DATA2PARAM2']
] as arrayTest
)
);
Cannot construct array with element type ARRAY<STRING> because nested arrays are not supported
This is the procedure, where I declare the variable and set it:
CREATE OR REPLACE PROCEDURE MY_DATASET.MY_PROCEDURE()
BEGIN
DECLARE tablesArray ARRAY<STRING>;
SET tablesArray = MY_DATASET.MY_FUNCTION();
END;
Cannot coerce expression BILLING_COMPARE.arrayTablesCartografiaToCompare() to type ARRAY<STRING>
How can I declare an Array of Arrays or what is the best way to do this?
An array of an array is not allowed. However, an array of a struct with an array is possible:
With test AS (
(
select [
struct(['DATA1','DATA1PARAM1'] as data),
struct(['DATA2','DATA2PARAM2'])
] as arrayTest
)
)
SELECT * from test, unnest(arrayTest) with offset
Related
I am trying to create a multi-column aggregate function that needs to accumulate all the column values for later processing.
CREATE OR REPLACE FUNCTION accumulate_scores(prev integer[][],l1 integer,
l2 integer,l3 integer) RETURNS integer[][] AS
$$
BEGIN
prev[1] = array_append(prev[1],l1);
prev[2] = array_append(prev[2],l2);
prev[3] = array_append(prev[3],l3);
return prev;
END
$$ LANGUAGE plpgsql;
CREATE AGGREGATE my_aggregate(integer,integer,integer)(
SFUNC = accumulate_scores,
STYPE = integer[][],
INITCOND = '{}'
);
select accumulate_scores(ARRAY[1]|| ARRAY[[1],[1]],2,3,4);
I get this error
ERROR: function array_append(integer, integer) does not exist
Hint: No function matches the given name and argument types. You might need to add explicit type casts.
How do i accumulate these values into a multi dimensional array?
Edit: i have tried with array_cat and get the same error. thought array_append might be right since prev[1] is a uni dimensional array
You function & aggregate function would "work" like this, but it would only create a 1-dimenstional array:
CREATE OR REPLACE FUNCTION accumulate_scores(prev integer[][]
,l1 integer
,l2 integer
,l3 integer)
RETURNS integer[][] AS
$func$
BEGIN
prev := prev || ARRAY[l1,l2,l3];
RETURN prev;
END
$func$ LANGUAGE plpgsql;
CREATE AGGREGATE my_aggregate(integer,integer,integer)(
SFUNC = accumulate_scores,
STYPE = integer[][],
INITCOND = '{}'
);
The declaration RETURNS integer[][] is equivalent to just RETURNS integer[]. For Postgres all arrays on the same base element are the same type. Additional brackets are for documentation only and ignored.
To actually produce a multi-dimensional array, you don't need a custom function. Just a custom aggregate function:
CREATE AGGREGATE array_agg_mult (anyarray) (
SFUNC = array_cat
,STYPE = anyarray
,INITCOND = '{}'
);
Then you can:
SELECT array_agg_mult(ARRAY[ARRAY[l1,l2,l3]]) -- note the two array layers!
from tbl;
More details here:
Selecting data into a Postgres array
This is how I understand the question
select array[
array_agg(l1),
array_agg(l2),
array_agg(l3)
]
from (values
(1, 9, 1, 2, 3), (2, 9, 4, 5, 6)
) s(id, bar, l1, l2, l3)
group by bar;
array
---------------------
{{1,4},{2,5},{3,6}}
In case somebody encount some issue following erwin's great answer.
before postgresql 14 follow Erwin's answer.
for postgresql 14, we need tiny tweak.
create or replace aggregate
array_agg_mult(anycompatiblearray)
(sfunc = array_cat,
stype = anycompatiblearray,
initcond = '{}');
I'm trying to store an array (not array ref) in a hash but it is treating the array in scalar context and only storing the last value of array in the $hash->{key}.
use Data::Dumper;
$h->{'a'} = ( 'str_1', 'str_2' );
print Dumper $h;
Output: $VAR1 = { 'a' => 'str_2' };
Why can't I store an array in hash-Key and access the array elements as $hash->{key}[index]
$h->{'a'} = [ 'str_1', 'str_2' ];
You can only store scalar as a hash value, and scalar can be simple value or array reference.
Check perldoc.
Values of a hash have to be scalar values, cannot be arrays or hashes. So you need to use array reference as the value of $h->{'a'}:
$h->{'a'} = [ 'str_1', 'str_2' ];
and access them by using
$h->{'a'}->[0]; # for 'str_1'
$h->{'a'}->[1]; # for 'str_2'
By the way, as pointed out by #RobEarl, you also can use the following syntax
$h->{'a'}[0]; # for 'str_1'
$h->{'a'}[1]; # for 'str_2'
See perlref for how to create and use different kind of references.
I can create an array of arrays:
select array[array[1, 2], array[3, 4]];
array
---------------
{{1,2},{3,4}}
But I can't aggregated arrays:
select array_agg(array[c1, c2])
from (
values (1, 2), (3, 4)
) s(c1, c2);
ERROR: could not find array type for data type integer[]
What am I missing?
I use:
CREATE AGGREGATE array_agg_mult(anyarray) (
SFUNC = array_cat,
STYPE = anyarray,
INITCOND = '{}'
);
and queries like:
SELECT array_agg_mult( ARRAY[[x,x]] ) FROM generate_series(1,10) x;
Note that you must aggregate 2-dimensional arrays, so you'll often want to wrap an input array in a single-element ARRAY[array_to_aggregate] array constructor.
If you work with php you can see the php have associative array (or array width string key) in programing lang.
For example:
$server['hostname'] = 'localhost';
$server['database'] = 'test';
$server['username'] = 'root';
$server['password'] = 'password' ;
// 2d array
$all['myserver']['hostname'] = 'localhost' ;
But can't find any default way to use associative array in delphi.
First I want find default way with out any output component or class .
Second if really I cant find with internal way I force choose output classes only.
I use Delphi XE3 , many thanks for your help.
edit:
I found one class here : http://www.delphipages.com/forum/showthread.php?t=26334
same as php , but any better way?
You can use TDictionary<string,string> from the Generics.Collections unit.
var
Dict: TDictionary<string,string>;
myValue: string;
....
Dict := TDictionary<string,string>.Create;
try
Dict.Add('hostname', 'localhost');
Dict.Add('database', 'test');
//etc.
myValue := Dict['hostname'];
finally
Dict.Free;
end;
And so on and so on.
If you want a dictionary that contains a dictionary, you can do use TDictionary<string, TDictionary<string,string>>.
However, when you do that you'll need to take special care over the lifetime of the dictionary items that are contained in the outer dictionary. You can use TObjectDictionary<K,V> to help manage that for you. You'd create one of these objects like this:
TObjectDictionary<string, TDictionary<string,string>>.Create([doOwnsValues]);
This TObjectDictionary<k,V> operates the same was as a traditional TObjectList with OwnsObjects set to True.
You can use tStrings and tStringList for this purpose, but 2d arrays are out of the scope of these components.
Usage;
var
names : TStrings;
begin
...
names := TStringList.Create;
...
...
names.values['ABC'] := 'VALUE of ABC' ;
...
...
end ;
I had solved the problem that simple way (example):
uses StrUtils;
...
const const_TypesChar : array [0..4] of String =
(
'I',
'F',
'D',
'S',
'B'
);
const const_TypesStr : array [0..4] of String =
(
'Integer',
'Float',
'Datetime',
'String',
'Boolean'
);
...
Value := const_TypesStr[ AnsiIndexStr('S', const_TypesChar) ];
// As an example, after execution of this code Value variable will have 'String' value.
//
Then in program we are using two arrays const_TypesChar and const_TypesStr as one associative array with AnsiIndexStr function.
The plus is that it's simple and that we don't need to change code in different places in program every time when we add elements to our arrays.
Look at ArrayS. You can use associative arrays which stores predefined type of data (integer, string, boolean, float), or any of them. For example, below I define an associative array of floats:
uses ArrayS;
var floats : IFltArray;
floats := CreateArray;
floats['first'] := 0.1;
floats['second'] := 0.2;
writeln( floats['second'] );
And so on.
Updated at 2020-03-15
Zipped source code
Ussage example in Russian
Is there a way in Delphi declaring an array of strings such as following one?
{'first','second','third'}
In XE7 you can declare a dynamic array constant like this:
const
MyArray: TArray<String> = ['First','Second','Third'];
try this
Const
Elements =3;
MyArray : array [1..Elements] of string = ('element 1','element 2','element 3');
You can use dynamic arrays and try this:
var
FMyArray: TArray<string>;
function MyArray: TArray<string>;
begin
if Length(FMyArray) = 0 then
FMyArray := TArray<string>.Create('One', 'Two', 'Three');
Result := FMyArray;
end;
While this does do a run-time initialization of a dynamic array on the heap, it also shows that Delphi supports a "pseudo-constructor" on dynamic arrays that allow in-place initialization. (NOTE: the above code isn't thread-safe).
Now all you need to do to find out the length of the array, is use the Length() standard function, or to find the allowed index range, use the Low() and High() standard functions.
If you're using an older version of Delphi, replace the TArray with your own dynamic-array string type such as:
type
TStringArray = array of string;
You can do this in a indirect way. Create a function like:
procedure assignStringArray(var rasVelden: ArrayOfString; const asVeldenIn: Array Of String);
var
iLengte, iT1: Integer;
begin
iLengte := Length(asVeldenIn);
SetLength(rasVelden, iLengte);
for iT1 := iLengte-1 downto 0 do
rasVelden[iT1] := asVeldenIn[iT1];
end;
and call this function like:
assignStringArray(asVelden, ['String1', 'String2', 'String3']);
where:
asVelden: ArrayOfString;