Converting Syntax from sqllite to postgresql - sqlite

I have a sqlLite database which contain in some field sql statement, this sql statement are needed to create some chart in an IOS Application.
Now I need to display this chart in a web application which use Postgresql
I need to find a script who convert from sqllite syntax to postgresql syntax
things like printf, current date etc...
I am asking if there is some ready to use script for this kind of conversion
PS : I am using Symfony for the back-end so PHP
Example:
SELECT
r.agent AS gebiet,
r.invoiceno AS rechnung,
r.infotext AS auftrag,
c.companyno AS kundenr,
c.companyname AS kunde,
r.itemno AS artikelnr,
r.itemtext AS artikel,
SUM(r.qty) || ' ' || r.unit AS menge,
printf('%.2f', SUM(r.turnover) / SUM(r.qty)) AS preis,
printf('%.2f', SUM(r.turnover)) || ' ' || r.currency AS gesamt,
'2' AS 'sys_align9',
'2' AS 'sys_align10',
'2' AS 'sys_align11'
FROM
invoices r
INNER JOIN
company c
ON
r.companyno = c.companyno
WHERE
r.agent = ?

Disclaimer: I don't know SQLite ;)
The query structure itself looks good, but two things will not work with Postgres:
I assume printf() formats the output to two decimals, so to_char() is probably what you are looking for
identifiers need to be enclosed in double quotes, not single quotes. So AS 'sys_align11' should be `AS "sys_align11" but the quotes are not required to begin with.
SELECT
r.agent AS gebiet,
r.invoiceno AS rechnung,
r.infotext AS auftrag,
c.companyno AS kundenr,
c.companyname AS kunde,
r.itemno AS artikelnr,
r.itemtext AS artikel,
SUM(r.qty) || ' ' || r.unit AS menge,
to_char(SUM(r.turnover) / SUM(r.qty), '0.00') AS preis,
to_char(SUM(r.turnover),'0.00') || ' ' || r.currency AS gesamt,
'2' AS sys_align9,
'2' AS sys_align10,
'2' AS sys_align11
FROM
invoices r
INNER JOIN
company c
ON
r.companyno = c.companyno
WHERE
r.agent = ?
If turnover is an integer (or bigin) you need to cast it to numeric, otherwise the division is done as an integer division, e.g. SUM(r.turnover)::numeric
As you are using an aggregat function you will need some kind of group by in Postgres - otherwise the result wouldn't be deterministic.
If invoiceno is the primary key of the invoices table, a `group by r.invoiceno' should be enough.

Related

Tag key & value using Teradata Regular Expression

I have a TERADATA dataset that resembles the below :
'Project: Hercules IssueType: Improvement Components: core AffectsVersions: 2.4.1 Priority: Minor Time: 15:25:23 04/06/2020'
I want to extract tag value from the above based on the key.
Ex:
with comm as
(
select 'Project: Hercules IssueType: Improvement Components: core AffectsVersions: 2.4.1 Priority: Minor' as text
)
select regexp_substr(comm.text,'[^: ]+',1,4)
from comm where regexp_substr(comm.text,'[^: ]+',1,3) = 'IssueType';
Is there a way to query without having to change the position arguments for every tag.
Also I am finding the last field a little tricky with date & time fields.
Any help is appreciated.
Thank you.
There's the NVP function to access Name/Value-pair data, but to split into multiple rows you need either strtok_split_to_table or regexp_split_to_table. The tricky part in your case are the delimiters, would be easier if they were unique instead of ' 'and ':':
WITH comm AS
(
SELECT 1 as keycol, -- should be a key column in your table, either numeric or varchar
'Project: Hercules IssueType: Improvement Components: core AffectsVersions: 2.4.1 Priority: Minor Time: 15:25:23 04/06/2020' AS text
)
SELECT id, tokennum, token,
-- get the key
StrTok(token,':', 1) AS "Key",
-- get the value (can't use StrTok because of ':' delimiter)
Substring(token From Position(': ' IN token)+2) AS "Value"
FROM TABLE
( RegExp_Split_To_Table(comm.keycol
,comm.text
,'( )(?=[^ ]+: )' -- assuming names don't contain spaces: split at the last space before ': '
, 'c')
RETURNS (id INT , tokennum INTEGER, token VARCHAR(1000) CHARACTER SET Latin)) AS dt

How can I bulk rename table columns in a SQLite database?

I created a whole bunch of SQLite database tables. Many columns in the tables have names with spaces, which I'm now realizing was not such a brilliant idea. Is there a way to write one command which will get rid of all spaces in all columns in all tables? I know I can do it one at a time (all potential duplicates seem to address this issue rather than my issue) but it's going to take me forever. Any ideas on how I can do this?
Use the following SQL to find all of the column names that contain spaces. I also included SQL to generate a new name.
SELECT t.name as tablename, c.name as badcol, replace(c.name, ' ','_') as newcolname
FROM sqlite_master t
JOIN pragma_table_info(t.name) c
WHERE t.type = 'table' AND c.name like '% %';
From here you would have to generate alter statements looking like this:
ALTER table <tablename> RENAME COLUMN <badcol> to <newcolname>;
While I cant figure how to directly pass the list of parms to the Alter table command you can use the following SQL to generate the alter commands for you then just copy/paste the result and execute the list of them.
SELECT ('ALTER TABLE ' || t.name || ' RENAME COLUMN ' || '[' || c.name || ']'
|| ' TO ' || '[' || REPLACE(c.name, ' ','_') || '];')
FROM sqlite_master t
JOIN pragma_table_info(t.name) c
WHERE t.type = 'table' AND c.name like '% %';
In this SQL I replaced the spaces in col names with underscores but you can see where you could replace the REPLACE function with the column renaming solution you desire.

Create a table as, where 'date condition' in dynamic PL/SQL

I got assigned the following task.
Assume we have a table A structured with an id column and a date column.
Write a procedure in PL/SQL that: takes as parameters the table name (in our case A) and a date D, creates a backup table named A_bck containing only the records of A with dates < D and removes from the table A all the records inserted in A_bck.
Here there is my code.
Unluckily I get this error:
Error report -
ORA-00904: "MAY": invalid identifier
ORA-06512: at line 41
ORA-06512: at line 80
00904. 00000 - "%s: invalid identifier"
If I try to achieve the same result using a where condition on the id column instead that on the date one, I have no problems.
Where is the mistake? Am I implementing it completely in the wrong way?
The problem you have is that as you're executing dynamic sql you're query is built up as a string. Oracle does not know that the date you've given is actually a date, it is simply being treated as part of the string. To solve this you should be able to do the following:
my_query := 'CREATE TABLE ' || table_name_backup || ' AS (SELECT * FROM ' || table_name || ' WHERE table_date < to_date(''' || backup_date || '''))';
This should sort out your issue for you. As a side note, you will probably want to change your "table_exists" query, as table names are all stored in upper case, e.g.
SELECT COUNT(*) INTO table_exists FROM USER_TABLES WHERE TABLE_NAME = upper(my_table);
Edit: Further explanation following comment
To explain why you don't have the above problem when using integers, it is important to remember that using execute immediate simply executes the given string as an SQL query.
For example:
declare
x INTEGER := 1;
i integer;
my_query VARCHAR2(256);
begin
my_query := 'select 1 from dual where 1 = ' || x;
EXECUTE IMMEDIATE my_query INTO i;
end;
my_query in the above example would be executed as:
select 1 from dual where 1 = 1
which is perfectly valid sql. In your example however, you were ending up with something like this:
CREATE TABLE abaco_bck AS (SELECT * FROM abaco WHERE table_date < 27-MAY-17)
As it isn't wrapped in quotes, or explicitly converted to a date, the SQL engine is trying to subtract "MAY" from 27, but it doesn't know what "MAY" is.
One other thing to mention, is that for some operations you could use bind variables instead of quotes (although you can't for DDL) e.g.
declare
lToday DATE := SYSDATE;
i INTEGER;
my_query VARCHAR2(256);
begin
my_query := 'select 1 from dual where sysdate = :1';
EXECUTE IMMEDIATE my_query INTO i USING lToday;
end;

Using nvarchar(MAX) to build query, but conversion fails in where clause

I have a stored procedure that uses a variable called #Command (nvarchar(MAX)). I then add parameters accordingly based on given input.
declare #Command nvarchar(max)
if(#CaseFileID IS NOT NULL)
BEGIN
select #Command='
select [ServerCredentialsID],[CaseFileID],EIKSLT.[LocationType],EPT.PaymentType,[TaskID],[DateActive]
,[LengthOfPurchase],[Username],[Password],[IPDomain],[Port],[DES],[Website],[AmountPaid],[Latitude]
,[Longitude],[HasAttachments],[TimeStamp],[CaseElement],[Temporary],[StatusID]
FROM Element17a_IKSServerCredentials EIKSSC
JOIN ElementsIKSLocationTypes EIKSLT ON EIKSSC.LocationBeingUsedID= EIKSLT.IKSLocationBeingUsedID
JOIN ElementsPaymentTypes EPT ON EIKSSC.PaymentMethodID=EPT.PaymentTypeID
where EIKSSC.CaseFileID='''+cast(#CaseFileID as nvarchar(MAX))+''' '
#CaseFileID is declared as an int, and in the table it is an int. When I try
where EIKSSC.CaseFileID = ' + #CaseFileID + ' '
then the value doesn't even show (in the error it looks like "EIKSSC.CaseFileID= '" )
I just don't get it.
NOTE: SQL Server 2008 Management Studio
It's because #CaseFileID is VARCHAR even though you don't show it.
Your IF should be
if(#CaseFileID > '')
And if even that doesn't work, then you need to swap to LEFT joins because INNER JOINs will remove records that cannot be matched in the other 2 tables.
Finally, because CaseFileID is an int, you don't need the quotes. Even though SQL Server will implicitly cast '9' to the integer 9 in the WHERE clause, it's just not necessary.
declare #Command nvarchar(max)
if(#CaseFileID > '')
BEGIN
select #Command='
select [ServerCredentialsID],[CaseFileID],EIKSLT.[LocationType],EPT.PaymentType,[TaskID],[DateActive]
,[LengthOfPurchase],[Username],[Password],[IPDomain],[Port],[DES],[Website],[AmountPaid],[Latitude]
,[Longitude],[HasAttachments],[TimeStamp],[CaseElement],[Temporary],[StatusID]
FROM Element17a_IKSServerCredentials EIKSSC
LEFT JOIN ElementsIKSLocationTypes EIKSLT ON EIKSSC.LocationBeingUsedID= EIKSLT.IKSLocationBeingUsedID
LEFT JOIN ElementsPaymentTypes EPT ON EIKSSC.PaymentMethodID=EPT.PaymentTypeID
where EIKSSC.CaseFileID='+cast(#CaseFileID as nvarchar(MAX))

Looking for a utility that converts a SQL statement into a dynamic SQL statement

I am looking for a utility that will convert Oracle SQL to a string that can executed dynamically.
Edit:
Yes, consider this simple SQL
SELECT * FROM TABLE
WHERE COLUMN_NAME = 'VALUE'
I have a utility which for T-SQL which converts the above SQL to a synamic SQL as follows:
BEGIN
DECLARE #Exe_String VarChar(2000)
DECLARE #Qt Char(1)
DECLARE #Cr Char(1)
SET #Qt = Char(39)
SET #Cr = Char(10)
SET #Exe_String = 'SELECT * FROM TABLE ' + #Cr
SET #Exe_String = #Exe_String + 'WHERE COLUMN_NAME = ' + #Qt + 'VALUE' + #Qt + '' + #Cr
PRINT #Exe_String
--Execute (#Exe_String)
END
Granted that the code generated good probably be better, yo get the idea, I hope.
I'm looking for the same type of conversion for Oracle SQL.
Here is a tool that I have used a couple of times. You will have to change the output a little to get it to run but it sure beats having to figure out how to escape all the single ticks.
Sql Tuning
After you click on the link it will take you right to the site and a page with sample SQL. Click the "Static SQL to Dynamic SQL" button and you can see how it works. Then input your own sql you want converted and click the button again. Remove the extra tick (') marks in the end and beginning of each line with the exception of the first and last line and pipes (|) don't need to be there either. Hope this helps.
As a raw translation of your T-SQL to PL/SQL
DECLARE
Exe_String VarChar(2000);
Qt CONSTANT Char(1) := CHR(39);
Cr CONSTANT Char(1) := CHR(10);
BEGIN
exe_string := 'SELECT * FROM TABLE '||Cr;
exe_string := exe_string ||
'WHERE COLUMN_NAME = ' || Qt || 'VALUE' ||Qt || '' ||Cr;
dbms_output.put_line(exe_string);
--
EXECUTE IMMEDIATE exe_string;
END;
The obvious difference is that in Oracle the concatenation operator for strings is || rather than +.
Personally, I have a little string manipluation package (let's call it pstring) that I'd use in a case like this - includes functions like enquote(string), standard constants for newline,tab,etc and the ability to do C-style text replacement.
exe_string :=
pstring.substitute_text('SELECT * FROM %s \n WHERE %s = %s',
table_name,column_name,pstring.enquote(value));
Have you considered using bind variables - i.e. :value - rather than dealing with escaping all the internal quotes? It's a good defence against SQL injection.
Obviously there's some difficulty if you have varying numbers of variables (you need to use DBMS_SQL to link them to the statement rather than a simple EXECUTE IMMEDIATE) but for your simple case it would look like this.
PROCEDURE (table_name IN VARCHAR2, column_name IN VARCHAR2)
IS
Exe_String VarChar(2000);
BEGIN
exe_string :=
pstring.substitute_text('SELECT * FROM %s \n WHERE %s = :value',
table_name,column_name);
dbms_output.put_line(exe_string);
--
EXECUTE IMMEDIATE exe_string USING pstring.enquote(value);
END;
Although of course you have to do something with the results of your SQL.
EXECUTE IMMEDIATE exe_string INTO lresult USING pstring.enquote(value);
Which is difficult when the shape of the table may differ - again, you have to look at Type 4 dynamic SQL (DBMS_SQL).

Resources