Odd convert_timezone behaviour in snowflake - snowflake-cloud-data-platform

I have the following issue, I wish to have events converted into a local_timestamp so I can run bucketing/cohorts however when I try to do a convert_timezone, I get Unknown timezone error. I tried TO_CHAR & TRIM too, didn't work. See screenshots:

I am able to reproduce it using following script. This is known and is happening for specific timezones value and I would suggest to log a support case.
create or replace table timezone_tbl (timezone_ varchar(50));
insert into timezone_tbl values ('UTC'),('Asia/Yangon');
select * from timezone_tbl;
select distinct timezone_, convert_timezone(timezone_,current_timestamp::string)
from timezone_tbl;

Thank you, indeed the support helped and told me that in December 2020 this is expected to be fixed. A workaround of my problem was as follows:
CASE
WHEN geo_timezone = 'Europe/Saratov' THEN 'Etc/GMT-4'
WHEN geo_timezone = 'Asia/Atyrau' THEN 'Etc/GMT-5'
WHEN geo_timezone = 'Asia/Qostanay' THEN 'Etc/GMT-6'
WHEN geo_timezone = 'Asia/Yangon' THEN 'Asia/Rangoon'
WHEN geo_timezone = 'Asia/Famagusta' THEN 'Asia/Nicosia'
WHEN geo_timezone = 'America/Nuuk' THEN 'America/Godthab'
WHEN geo_timezone = 'America/Punta_Arenas' THEN 'America/Santiago'
ELSE geo_timezone END

Related

Delphi FireDAC TFDQuery SQL Server DataTime filter problem

For the life of me, it seems I can't filter my TFDQuery using a DateTime field/format. I have this query that needs to "import" filters from a component (cxGrid), among them are:
"Date = " (DateTimeField);
"Value = " (FloatField);
"Supplier = " (StringField);
(And a few others, but those are the more important ones). Date is seconds sensitive, so it has HH:MM:SS, this is necessary for stock/contability purposes.
Now what I mean about "importing" filters is that I'm using the same filters as the ones current marked on a cxGrid. I do so using this simple method:
Filter := cxGridDBTableView.DataController.Filter.FilterText;
Which gives me a string of all the filters currently in use in that cxGrid.
I then toss this string in the filters of my query as in:
MyTFDQuery.Filtered := False;
MyTFDQuery.Filter := Filter;
MyTFDQuery.Filtered := True;
This posed a problem with Value, as we had a display format changing the float to a different format (from, let's say, 2.4 to 2,40) but this has already been fixed. Supplier and the other fields all worked like a charm, mostly because they didn't have a mask/display format.
My problem is when running the DateTime field (Date) filter, I get this error:
[FireDAC][Stan][Eval]-114. Expected []
This field has no display formats or masks of any kind.
I did try searching for this error code online, and couldn't find anything. I did try to change the format of the Date filter, seeing as many people had issues with the format. I have tried all forms of:
MyTFDQuery.Filter := 'Date = ''2021-01-01 10:00:00'''
MyTFDQuery.Filter := 'Date = {dt 2021-01-01 10:00:00}'
MyTFDQuery.Filter := 'Date = ' + Chr(39) + '2021-01-01 10:00:00' + Chr(39)
MyTFDQuery.Filter := 'Date = {CONVERT(''2021-01-01 10:00:00'', DATETIME)}
and many others that I can't recall from the top of my head, right now.
And also tried several different formats for the date... Such as:
YYYY-MM-DD
YYYY-DD-MM
DD-MM-YYYY
MM-DD-YYYY
Or even the separators for that date. I've tried ' - '; ' / '; ' . ' and the such (like 24.02.1982 instead of 24/02/1982). and kept on trying different ways to make this work, with different combinations.
When I searched about this issue online, specially in "how to filter a dataset/tfdquery by datetime", most people were being told to use different formats for the date/datetime to make it work. It seemed everyone had a different solution for this.
I'm not sure what to try anymore. Is this somehow connected to regional settings, as one search result pointed out? Where would those settings be from? The Delphi IDE? FireDAC? The DB I use? Is there something I'm missing?
Basically I want to know what format I should be using to filter my TFDQuery.
Thank you all for reading so far, any help would be highly appreciated. I hope the question is straightforward enough.
PS: I'm sorry for anything wrong I made have done in the making of this question. English is not my native language, and it's been a really long week. Thank you for the patience.
UPDATE: I've identified the error with a lot of guesswork. The milliseconds bit of the datetime is being taken into account when the filter is going to be applied to the dataset, and the cxGrid component would round the seconds (e.g changing '2021-02-01 18:05:03.822' to '2021-02-01 18:05:04').
That way, when the Date = '2021-02-01 18:05:04' would filter something, it wouldn't show up anything. It wasn't an issue with formatting, but rather with equality of datetimes.
To fix this, I followed Brian's advice and made the change:
cxGridDBTableView.DataController.Filter.DateTimeFormat := 'yy-mm-dd hh:mm:ss.zzz'
Now the millisecs are being taken from the filter, and the rounding ignored. Unfortunatelly I'm stuck on the error it gives:
[FireDAC][Stan][Eval]-118. Couldn't convert variant of type (UnicodeString) into type (Date)
Any further help would be highly appreciated.
I've found the "solution" to this problem. I simply assumed the query didn't accept the string filter with milliseconds, maybe some compatibility issues. I'm leaving this here in hopes that someone with a problem like mine can solve it fast, and maybe someone else can improve on this and make it more elegant/efficient.
I broke the string and inserted in a stringlist for easy management:
MyStringListFilters.LineBreak := ' AND ';
MyStringListFilters.Text := Filter;
This would turn a filter's string from:
((Date = ''28/09/2022 18:22:44.789'') OR (DATE = ''11/02/2019 07:18:03.122'')) AND ((Value = 2,4) OR (Value = 7,9)) AND (SUPPLIER = ''My Supplier Name Ltda'')
To:
((Date = ''28/09/2022 18:22:44.789'') OR (DATE = ''11/02/2019 07:18:03.122''))
((Value = 2,4) OR (Value = 7,9))
(SUPPLIER = ''My Supplier Name Inc'')
Now fixing the values is easy by just using a StringReplace:
While i < MyStringListFilters.Count do
if (Copy(MyStringListFilters[i], 2, 5) = 'Value') or (Copy(MyStringListFilters[i], 3, 5) = 'Value') then
StringReplace(MyStringListFilters[i], ',', '.', [rfReplaceAll]);
(When there is two or values, there will be an extra parentheses in front of the string).
Fixing the Date was a bit harder. I had to insert the string inside another string list, and break it up the same way:
//inside of the same while
if (Copy(MyStringListFilters[i], 2, 4) = 'Date') or (Copy(MyStringListFilters[i], 3, 4) = 'Date') then
begin
MyStringListDates.LineBreak := ' OR ';
MyStringListDates.Text := MyStringListFilters[i];
//it keeps on going...
Which further breaks the date string to:
((Date = ''28/09/2022 18:22:44.789'')
(Date = ''11/02/2019 07:18:03.122''))
Be aware: We have to remove the parentheses in the first filter and in the last as well if there is two or more Date filters. We also have to set things up as it was by the end of the loop. Do remember to always increment the index integer of both whiles.
//This happens inside the first while...
while j < MyStringListDates.Count do
begin
TempDate := Copy(MyStringListDates[j], 10, 19);
//This pulls the whole second, ignoring milliseconds from the DB.
MyStringListDates[j] := '((Date >= ' + QuotedStr(TempData) + ') and (Date < ' + QuotedStr(DateTimeToStr(IncSecond(StrToDateTime(TempData)))) + '))';
FixedDate := FixedDate + MyStringListDates[j];
if FixedDate = '' then
begin
// Puts the first parentheses back.
if MyStringListDates.Count > 1 then
FixedDate := '(';
FixedDate := FixedDate + MyStringListDates[j];
end
else
FixedDate := FixedDate + ' OR ' + MyStringListDates[j];
Inc(j);
end
//Remember to add the last parentheses here, if there is more than 1 Date Filter.
I would like to thank #Brian for their help with this solution. I didn't notice the component could be changed so the DateTime would come differently.
I would also like to thank #marc_s for editing the original question. This is my first question on the platform ever, so I didn't know what I was doing (Still don't. Sorry).
Also a special thanks to #Uwe Raabe, I've also used their answer on how to split strings using a multiple character delimiter on this problem. Here's the link to that question they answered:
How to split string by a multi-character delimiter?

Is there any way to optimize this query?

I need to optimize the following query:
IF object_id('tempdb..#TAB001') IS NOT NULL
DROP TABLE #TAB001;
select *
into #TAB001
from dbo.uvw_TAB001
where 1 = 1
and isnull(COD_CUSTOMER,'') = isnull(#cod_customer,isnull(COD_CUSTOMER,''))
and isnull(TAXCODE,'') = isnull(#taxcode, isnull(TAXCODE,''))
and isnull(SURNAME,'') = isnull(#surname,isnull(SURNAME,''))
and isnull(VATCODE,'') = isnull(#vatCode,isnull(VATCODE,''))
The goal is to improve the performance of this query.
It is currently quite fast but I would like to speed it up even more.
This query has the optional parameters for which it is necessary to make a query that regardless of whether all or 1 parameter is set, returns results in the shortest possible time.
What you have here is known as a "catch-all" or "kitchen sink" query, which need a little helping hand sometimes.
Firstly, you need to get rid of those ISNULLs; they are making the query non-SARGable. Also, I would suggest getting rid of the SELECT * and limiting the query to the columns you need.
Then, finally, we can add OPTION (RECOMPILE) to the query; why is discussed in the articles I linked above. This gives you the following:
SELECT * --Replace with Column Names
INTO #TAB001 --Do you actually need to do this?
FROM dbo.uvw_TAB001
--Removed WHERE 1 = 1 as it's always true, thus pointless
WHERE (COD_CUSTOMER = #cod_customer OR #cod_customer IS NULL)
AND (TAXCODE = #taxcode OR #taxcode IS NULL)
AND (SURNAME = #surname OR #surname IS NULL)
AND (VATCODE = #vatCode OR #vatCode IS NULL)
OPTION (RECOMPILE);
Note I am assuming that when a variable (for example #cod_customer) has the value NULL you mean that the variable should be "ignored" and not matched against NULL.
If you actually want {Column} = #{Variable} including NULL then use SQL with the format below instead:
({Column} = #{Variable} OR ({Column} IS NULL AND #{Variable} IS NULL))

SSMS Error "An expression of non-boolean type specified in a context where a condition is expected, near '('"

I am getting the titled error from a number of SQL Server views I am trying to create. They are modified from a MS Access database I'm upgrading to use SQL as the back end. See SQL below:
SELECT dbo.Site_Info_All.SiteID,
IIf(dbo.Site_Info_All.Fixed_Charge, N'Yes', N'No') AS [Fixed Charge],
dbo.Site_Info_All.Fixed_Charge_Date, dbo.MG_Definition.MG_Definition
FROM dbo.MG_Definition INNER JOIN
dbo.Site_Info_All ON dbo.MG_Definition.MG_DefinitionID =
dbo.Site_Info_All.MG_DefinitionID
It looks as though I'm being told that the Fixed_Charge field is not boolean, except that it is. I'm encountering this issue with multiple views. What am I doing wrong?
It's not boolean. It's a bit. :)
A bit column doesn't directly evaluate to true or false, the way a bool does in other languages. You actually have to compare it to another bit value to return the boolean value.
declare #bit bit = 1;
if (#bit) print '#bit was true'; -- this does not work
if (#bit = 1) print '#bit = 1 was true'; -- this works
What you want is:
... IIf(dbo.Site_Info_All.Fixed_Charge = 1, N'Yes', N'No') ...
SELECT dbo.Site_Info_All.SiteID,
IIf(dbo.Site_Info_All.Fixed_Charge = 1, N'Yes', N'No') AS [Fixed Charge],
dbo.Site_Info_All.Fixed_Charge_Date,
dbo.MG_Definition.MG_Definition
FROM dbo.MG_Definition
INNER JOIN dbo.Site_Info_All ON dbo.MG_Definition.MG_DefinitionID = dbo.Site_Info_All.MG_DefinitionID
In the end, I decided that IIF simply wasn't working for whatever reason. An answer to that would be very welcome, btw.
I used
SELECT dbo.Site_Info_All.SiteID,
CASE WHEN dbo.Site_Info_All.Fixed_Charge = 1
THEN N'Yes'
ELSE N'No'
END AS [Fixed Charge], dbo.Site_Info_All.Fixed_Charge_Date,
dbo.MG_Definition.MG_Definition
FROM dbo.MG_Definition INNER JOIN
dbo.Site_Info_All ON dbo.MG_Definition.MG_DefinitionID =
dbo.Site_Info_All.MG_DefinitionID
That gave me the results I was after, but only after pulling out what little hair I have left.

Why I can't join partial tables into one in Sqlite3?

I decomposed a large table into five tables based on BCNF and I tried to join them all together to check if I lost something or not.
I used this sql statement in Sqlite3
Select
spart.Sno, spart.Sname,
cpart.Cno, CtoT.Cname,
CtoT.Tno,tpart.Tname,
scorepart.Degree
from spart, cpart, CtoT, tpart, scorepart
where
cpart.Cname = CtoT.Cname
spart.Sno = scorepart.Sno
CtoT.Tno = tpart.Tno
cpart.Cno = scorepart.Cno;
And I got Error: near "spart": syntax error
Could anybody help me out?
Try this:
Select
spart.Sno, spart.Sname,
cpart.Cno, CtoT.Cname,
CtoT.Tno,tpart.Tname,
scorepart.Degree
from spart, cpart, CtoT, tpart, scorepart
where
(cpart.Cname = CtoT.Cname)
and (spart.Sno = scorepart.Sno)
and (CtoT.Tno = tpart.Tno)
and (cpart.Cno = scorepart.Cno);
I'm not sure the parentheses are really needed. I've forgotten the syntax rules.

Passing NULL value into parameterized delphi SQL server query

I am trying to pass in a null value to a TSQLDataset parameter. The query has the form:
Query_text:='MERGE INTO [Table]
USING (VALUES (:A,:B)) AS Source (Source_A, Source_B)
....
WHEN MATCHED THEN
UPDATE SET A = :A
WHEN NOT MATCHED THEN
INSERT(A, B) VALUES (:A,:B);
SQL_dataset.CommandType:=ctQuery;
SQL_dataset.CommandText:=Query_text;
SQL_dataset.ParamByName('A').AsString:='A';
SQL_dataset.ParamByName('B').AsString:={ COULD BE NULL, OR A STRING };
SQL_dataset.ExecSQL;
Parameter B is nullable, but is also a foreign key. If the user enters something in this field, then B must be validated against values in another table. If it is blank then I want it to be ignored. I was passing in '', but this obviously produces a FK violation error.
I tried:
SQL_dataset.ParamByName('B').Value:=Null;
..but then I get a "dbexpress driver does not support the tdbxtypes.unknown data type" error.
I also tried:
SQL_dataset.ParamByName('B').DataType:=ftVariant;
SQL_dataset.ParamByName('B').Value:=Null;
..but then got "dbexpress driver does not support the tdbxtypes.variant data type" error.
Not sure what I am doing wrong, any help would be appreciated. I am currently drawing up a parameter list based on whether the string is populated or not, and this works well; it's just a bit clunky (in my actual query) as there are quite a few parameters to validate.
I am using Delphi XE4 and SQL server 2012.
Update:
Thanks for all the help, your suggestions were right all along, it was something else that produced that 'dbexpress driver' error. I was creating a 'flexible' parameter list in an effort to get around my problem, and this caused the exception:
Parameter_string:='';
If B<>'' then Parameter_string:='B = :B,'
Query_text:='MERGE ...'
'...'
'UPDATE SET A = :A, '+Parameter_string+' C = :C' ....
... the idea being that if B is blank then the parameter won't be 'listed' in the query.
This doesn't work, or my implementation of it doesn't work (not sure why, I'm obviously missing a step somewhere).
Anyway, the working code:
Query_text:='MERGE ...'
'...'
'UPDATE SET A = :A, B = :B, C = :C' ....
SQL_dataset.CommandType:=ctQuery;
SQL_dataset.CommandText:=Query_text;
If B<>'' then
begin
SQL_dataset.ParamByName('B').AsString:='B';
end
else
begin
SQL_dataset.ParamByName('B').DataType:=ftString;
SQL_dataset.ParamByName('B').Value:=Null;
end;
what about:
SQL_dataset.ParamByName('B').Clear;
If I recall correctly, the db-null equivalent in Delphi is Variants.Null
Usual approach would be using parameters once per query and assign the appropriate datatype.
Value may be assigned to NULL.
var
Query_text:String;
begin
Query_text:='Declare #A varchar(100) ' // or e.g. integer
+#13#10'Declare #B varchar(100)'
+#13#10'Select #A=:A'
+#13#10'Select #B=:B'
+#13#10'Update Adressen Set Vorname=#A,Strasse=#B where Name=#B';
SQL_dataset.CommandType := ctQuery;
SQL_dataset.CommandText := Query_text;
SQL_dataset.Params.ParseSQL(SQL_dataset.CommandText,true);
Showmessage(IntToStr(SQL_dataset.Params.Count));
SQL_dataset.ParamByName('B').DataType := ftString;
SQL_dataset.ParamByName('B').Value := 'MyText';
SQL_dataset.ParamByName('A').DataType := ftString; // or e.g. ftInteger
SQL_dataset.ParamByName('A').Value := NULL;
SQL_dataset.ExecSQL;
end;

Resources