string/text storage limits in a sqlite3 database - ruby-on-rails

I have a note field of string type in one of my models in my sqlite3 database, but I realized that I needed to store more text than string would allow.
I just ran a migration changing the type of the field from string to text. Looking at my database, it says that the type is now text(255), whereas before it was varchar(255).
What does the 255 mean? Is that a character limit? If so, would I have the same storage problems as before? How would I fix this?
Here is the migration I used to change the field type
change_column(:posts, :note, :text)

SQLite does not enforce text storage limits. If you declare a column VARCHAR(1) or TEXT(1) you still can store some very long blob of 500 Megabytes inside it. Even though that is not adviseable.
~$ sqlite
SQLite version 3.7.2
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> create table foo ( bar text(3));
sqlite> insert into foo values ('aeiou');
sqlite> select * from foo;
aeiou

You should just make your storage type text and not put any limit on it. The 255 denotes the maximum number of characters allowed in the field.

Related

Rails 6, float or bigint column types being treated as integer by ActiveRecord

I need to accept very large integer values on a postgres column on a table pre_transaction. The column name is give_amount.
I tried changing the column type to bigint with:
change_column :pre_transactions, :give_amount, :bigint
but I still get the following error when I try to save the record even after restarting the console:
ActiveModel::RangeError (1000000000000000000000 is out of range for ActiveModel::Type::Integer with limit 8 bytes)
I also realized that if I run PreTransaction in the rails console, the bigint columns are shown as integer columns (same for foreign keys that are stated as bigint in the schema but appear as integer on rails c), which is weird.
That's why I then changed the column type to float. Now when I run PreTransaction in the rails console I do see the column as type float but now when I try to save the record it saves, but rounding up to 1.0.
So, how can I do to store very large integers in the database?
Instead of :bigint use the :decimal type. It avoids float rounding inconsistencies and allows for large numbers to be ok.

Rails ActiveRecord SQlite3 datatype mismatch error on change_column from string to text

I am trying to change the datatype of a column from string to id. But SQlite3 is giving me a hard time. This is the only line in my migration:
change_column :containers, :title, :text
When the migration is running I'm getting an error of datatype mismatch:
SQLite3::MismatchException: datatype mismatch: INSERT INTO "acontainers"
I am pretty sure this is because of ActiveRecord creating a temporary table that has a id field with datatype INT while the original table actually has a datatype VARCHAR as can be seen here:
CREATE TEMPORARY TABLE "acontainers" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
The problem is that I have no idea how to get around this. Any input is greatly appreciated!
Looks like a bug in the SQLite wrapper.
You can try to update to the latest version if you're not using the one
As a workaround you can do the migration in multiple steps:
Create a new column
Write to both columns
Backfill data from the old column to the new column
Move reads from the old column to the new column
Stop writing to the old column
Drop the old column
It is also a safer approach as change_column may cause downtimes and errors
You can read more about it in this gem description

Informix select into external syntax error

Can somebody please tell me what is the problem with the following informix statement :
SELECT * FROM
(some big query here)
INTO EXTERNAL empdata(selected_date date, land char, grund integer, some_user varchar, nr decimal(15))
USING (DATAFILES("DISK:/usr1/tbodan.out"))
I get a syntax error near INTO EXTERNAL empdata.
UPDATE
Informix version is 11.7 and omitting the column definition only brings the following error Error: Virtual column must have explicit name.
You need to follow the documented syntax at INTO EXTERNAL clause.
I think your problem is that you tried to provide column names and data types for the table.
This SQL worked for me:
SELECT * FROM elements
INTO EXTERNAL ext_elements
USING (DATAFILES("DISK:/Users/jleffler/tmp/ext-elements.table"))
This SQL did not, generating a -201 "A syntax error has occurred" error:
SELECT * FROM elements
INTO EXTERNAL ext_elements(atomic_number INTEGER, symbol CHAR(3),
name CHAR(20), atomic_weight DECIMAL(8,4),
pt_period SMALLINT, pt_group CHAR(2), stable CHAR(1))
USING (DATAFILES("DISK:/Users/jleffler/tmp/ext-elements.table"))
Testing on a Mac running macOS Sierra 10.12.5, using Informix 12.10.FC4.
Ok,so the problem was actually in the select query.
The query returns more columns that do not have an explicit name and are tagged as "expression" that is why the Error: Virtual column must have explicit name. popped up.
I solved this by using aliases for those columns. Then used the syntax suggested here.

Rails reports can't find a column that is there

I am currently trying to do a complicated WHERE search on a table using Rails, the trouble is I get the error:
PG::Error: ERROR: column "email" does not exist
LINE 1: SELECT "bans".* FROM "bans" WHERE (Email='' AND IP='' AND (...
^
: SELECT "bans".* FROM "bans" WHERE (Email='' AND IP='' AND (Username='NULL' ))
And I know that column actually exists, and doing a rails dbconsole gives me the following:
Jungle=> select * from bans;
id | Username | IP | Email | Reason | Length | created_at | updated_at
----+----------+----+-------+--------+--------+------------+------------
(0 rows)
So this is definatly in the database, has anyone had any experience with this?
SQL column names are case insensitive unless quoted, the standard says that identifiers should be normalized to upper case but PostgreSQL normalizes to lower case:
Quoting an identifier also makes it case-sensitive, whereas unquoted names are always folded to lower case. For example, the identifiers FOO, foo, and "foo" are considered the same by PostgreSQL, but "Foo" and "FOO" are different from these three and each other. (The folding of unquoted names to lower case in PostgreSQL is incompatible with the SQL standard, which says that unquoted names should be folded to upper case. Thus, foo should be equivalent to "FOO" not "foo" according to the standard. If you want to write portable applications you are advised to always quote a particular name or never quote it.)
You're referencing Email in your SQL:
SELECT "bans".* FROM "bans" WHERE (Email='' ...
but PostgreSQL is complaining about email:
column "email" does not exist
Your unquoted Email is being treated as email because PostgreSQL normalizes identifiers to lower case. Sounds like you created the columns with capitalized names by double quoting them:
create table "bans" (
"Email" varchar(...)
...
)
or by using :Email to identify the column in a migration. If you quote a column name when it is created, then it is not normalized to lower case (or upper case in the SQL standard case) and you'll have to double quote it and match the case forever:
SELECT "bans".* FROM "bans" WHERE ("Email"='' ...
Once you fix Email, you'll have the same problem with IP, Username, Reason, and Length: you'll have to double quote them all in any SQL that references them.
The best practise is to use lower case column and table names so that you don't have to worry about quoting things all the time. I'd recommend that you fix your table to have lower case column names.
As an aside, your 'NULL' string literal:
SELECT "bans".* FROM "bans" WHERE (Email='' AND IP='' AND (Username='NULL' ))
-- -------------------->------------------>---------->---------------^^^^^^
looks odd, are you sure that you don't mean "Username" is null? The 'NULL' string literal and the NULL value are entirely different things and you can't use = or != to compare things against NULL, you have to use is null, is not null, is distinct from, or is not distinct from (depending on your intent) when NULLs might be in play.
It doesn't look like you're error is from a test database but if so try rake db:test:prepare.
In general, be aware that you have 3 databases - Test, Development, Production. So it's easy to get them mixed up and check the wrong one.
I had the same problem here,
but as mu-is-too-short said, PostgreSql can be told to
search with case sensitivity on columns names.
So by implemented this code I managed to bypass the same error that you're facing:
Transaction.find(:all,:conditions => ["(date between ? and ?) AND \"Membership_id\" = ?", Time.now.at_beginning_of_month, Time.now.end_of_month,membership.id])
Noticed the \" sign srrounding the column name? Well.. as annoying as it is, that's the fix to this problem.

How to convert a table column to another data type

I have a column with the type of Varchar in my Postgres database which I meant to be integers... and now I want to change them, unfortunately this doesn't seem to work using my rails migration.
change_column :table1, :columnB, :integer
Which seems to output this SQL:
ALTER TABLE table1 ALTER COLUMN columnB TYPE integer
So I tried doing this:
execute 'ALTER TABLE table1 ALTER COLUMN columnB TYPE integer USING CAST(columnB AS INTEGER)'
but cast doesn't work in this instance because some of the column are null...
any ideas?
Error:
PGError: ERROR: invalid input syntax for integer: ""
: ALTER TABLE table1 ALTER COLUMN columnB TYPE integer USING CAST(columnB AS INTEGER)
Postgres v8.3
It sounds like the problem is that you have empty strings in your table. You'll need to handle those, probably with a case statement, such as:
execute %{ALTER TABLE "table1" ALTER COLUMN columnB TYPE integer USING CAST(CASE columnB WHEN '' THEN NULL ELSE columnB END AS INTEGER)}
Update: completely rewritten based on updated question.
NULLs shouldnt be a problem here.
Tell us your postgresql version and your error message.
Besides, why are you quoting identifiers ? Be aware that unquoted identifiers are converted to lowercase (default behaviour), so there might be a problem with your "columnB" in your query - it appears quoted first, unquoted in the cast.
Update: Before converting a column to integer, you must be sure that all you values are convertible. In this case, it means that columnB should contains only digits (or null).
You can check this by something like
select columnB from table where not columnB ~ E'^[0-9]+$';
If you want your empty strings to be converted to NULL integers, then run first
UPDATE table set columnB = NULL WHERE columnB = '';

Resources