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

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.

Related

Ambiguity between column alias and another column's name

I have got some tables with overlapping column names and I want to combine those columns into one column with the same name as alias, e.g.
select a.name || " " || b.name as name from a join b
This works fine. However, if I want to order them, e.g.
order by lower(name) asc
I get the error ambiguous column name: name, because sqlite doesn't know whether to use a's, b's or the selection's name column. My question is whether it is possible to specifically chose the selection's name column (without giving it a different alias)? Maybe there is some nice <keyword> such that <keyword>.name results in the selection's name column. Or is there really no better solution than
with tmp as (select tmp_a.name || " " || tmp_b.name as name from tmp_a join tmp_b)
select name from tmp order by lower(name) asc
I don't think that the use of the CTE or a subquery is not a good solution.
If you don't like them, the only way to do it is to repeat the expression in the ORDER BY clause:
select a.name || ' ' || b.name as name
from a join b
on ......
order by lower(a.name || ' ' || b.name)

Converting Syntax from sqllite to postgresql

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.

Using column values from one table within a select clause from another table

I have an Oracle table called: col_mapping where a column in this table has the column values of columns from another table.
Example data of table: col_mapping
ID DESCR COL_VALS
------------------------------
1 LABEL COL_1
2 NAME_ADDR COL_2:COL_3
3 SALARY COL4
Based on the above table, I now would like to go through each record in col_mapping and use the COL_VALS as part of my
select COL_VALS from other_tab
obviously, where there is more than one value like COL_2:COL_3, need to replace the ':' with a ','
SELECT COL_1 from other_tab;
SELECT COL_2,COL_3 from other_tab;
SELECT COL_4 from other_tab;
You can generate and execute insert statements based on the col_vals value using dynamic SQL, inside a cursor loop over the col_mappings rows:
begin
for r in (select replace(col_vals, ':', ',') as cols from col_mapping) loop
dbms_output.put_line('insert into staging_tab(' || r.cols || ')'
|| ' select ' || r.cols || ' from other_tab');
execute immediate 'insert into staging_tab(' || r.cols || ')'
|| ' select ' || r.cols || ' from other_tab';
end loop;
end;
/
The cursor just gets the cols_val value, replacing colon with comma. The generated insert uses that modified cols_val as both the insert column list and the select list - since you said the staging table will match the other_tab structure.
The dbms_output line is just so you can see the generated statements - it ins't necessary for the code to run, and you'll need to set serveroutput on or equivalent to see it anyway. With that enabled, running that block using your example mapping data shows:
PL/SQL procedure successfully completed.
insert into staging_tab(COL_1) select COL_1 from other_tab
insert into staging_tab(COL_2,COL_3) select COL_2,COL_3 from other_tab
insert into staging_tab(COL4) select COL4 from other_tab
What you'll end up with is the data from each row in other_tab spread across multiple rows in staging_tab, with lots of null values. Hopefully that's what you intended.

select the union of several tables together in a single step

I am very new to Oracle 11g and am trying to generate a large string by appending text for each column in a select statement and using a cursor to store the results. However I want the last statement to not have a union all included. The final result I want to build large string of each row generated or simply execute the result if possible.
Note: column1 has a list of schemas that I am interested in.
select 'select * from ' || column1 || '.' || column2 || ' union all ' from mytable
This is where column1 is the schema, column2 is the table name.
What is the simplest way to generate the final string without using rtrim to remove the last string. And is there a simple way to append all these rows together in the string automatically?
The final goal is to actually just execute the union into a resulting cursor.
If you're querying in a loop anyway I wouldn't try to construct the string as part of the select at all; I'd do it all within the loop. Something like (untested):
declare
str varchar2(32768);
begin
for rec in (select column1, column2, rownum as rn from mytable)
loop
if rec.rn > 1 then
str := str || ' union all ';
end if;
str := str || 'select * from "' || rec.column[ || '"."' || rec.column2 ||'"';
end loop;
-- do something with str e.g. display to verify the syntax
-- before using in a cursor
dbms_output.put_line(str);
end;
Rather than adding union all to the end of every row except the last one,the rn check means it's added to the start of every row except the first one, which is easier to detect.
I've also wrapped the schema and table names in double quotes, just in case you have to deal with any quoted identifiers. But if your stored values don't match the case of the owners and table names in all_tables this will cause a problem rather than solve it.

ISNULL with SQL Server 2008

I want to use ISNULL with all columns of a table.
Like this
SELECT ISNULL(* , 'NA') FROM #tbl
I know its a wrong way I have to specify each column name separately to use ISNULL.
But in my case #tbl is a temporary table and columns are created dynamically
like this:
EXEC ('ALTER TABLE #tbl ADD [' + #bno + '] varchar(30)')
Due to this I can't use column names in select query because column names are always different.
So what should I do?
Change your dynamic SQL to:
EXEC ('ALTER TABLE #tbl ADD [' + #bno + '] varchar(30) NULL DEFAULT(''NA'')')
Try to get fields of your temprary table from the tempdb.sys.columns table then iterate over these:
select c.*
from tempdb.sys.columns c
inner join tempdb.sys.tables t ON c.object_id = t.object_id
where t.name like '#TableName%'

Resources