Lazarus fails to generate proper InsertSQL, how to remedy? - sqlite

I'm using Lazarus and trying to insert payment records into a SQLite database, but apparently InsertSQL isn't autogenerating the correct INSERT statement, and I have discovered that I can't simply assign parameters to .InsertSQL by using .ParamByName like I can to the .SQL property.
My database has tables of Customers and Payments. The Payments table is as follows:
Pay_Key: Primary key, Integer, Unique, Not NULL. Identifies a single payment row in the table.
Pay_Customer: Integer, Not NULL. Foreign-key linked to an integer-type Not NULL primary key in my Customers table.
Pay_Sum: Integer. (Yes, I'm storing the payment sum as integer, but this isn't really important here.)
I'm using SELECT * FROM Payments WHERE Pay_Customer=:CustomerKey in my SQLQuery.SQL, and assigning :CustomerKey each time programmatically via SQLQuery.ParamByName('CustomerKey').Text. This lets me navigate existing records nicely in a DBGrid, but when I try to insert a new payment, the operation fails on the "Pay_Customer Not NULL" condition. Apparently Lazarus doesn't know what value to use in the Pay_Customer field, since I passed it programmatically.
Is there a way to remedy this? I can write my own InsertSQL if need be, I just don't understand how I can pass this customer parameter to it. I would very much like to use InsertSQL/UpdateSQL/DeleteSQL, since they would make it easy to use stock DBGrid/DBNavigator components and logic for what I'm doing.
Thanks for any suggestions, and sorry for being so verbose about my question.
-Sam
Edit: I'm using Lazarus 1.6 (FPC 3.0.0). I have enabled foreign keys in SQLite in SQLite3Connection.Params (foreign_keys=on)

Related

How to get the id of a newly-created value with Diesel and SQLite?

Diesel's SqliteBackend does not implement the SupportsReturningClause trait, so the get_result method cannot be used to retrieve a newly created value.
Is there another way to find out the id of the inserted row? Python has a solution for this. The only solution I've found so far is to use a UUID for ids instead of an autoincrement field.
The underlying issue here is that SQLite does not support SQL RETURNING clauses which would allow you to return the auto generated id as part of your insert statement.
As the OP only provided a general question I cannot show examples how to implement that using diesel.
There are several ways to workaround this issue. All of them require that you execute a second query.
Order by id and select just the largest id. That's the most direct solution. It shows directly the issues with doing a second query, as there can be a racing insert at any point in time, so that you can get back the wrong id (at least if you don't use transactions).
Use the last_insert_rowid() SQL function to receive the row id of the last inserted column. If not configured otherwise those row id matches your autoincrement primary integer key. On diesel side you can use no_arg_sql_function!() to define the underlying sql function in your crate.

Tying table records together in SQLite3

I am currently working on a database structure in SQLite Studio (not sure whether that's in itself important, but might as well mention), and error messages are making me wonder whether I'm just going at it the wrong way or there's some subtlety I'm missing.
Assume two tables, people-basics (person-ID, person-NAME, person-GENDER) and people-stats (person-ID, person-NAME, person-SIZE). What I'm looking into achieving is "Every record in people-basics corresponds to a single record in people-stats.", ideally with the added property that person-ID and person-NAME in people-stats reflect the associated person-ID and person-NAME in people-basics.
I've been assuming up to now that one would achieve this with Foreign Keys, but I've also been unable to get this to work.
When I add a person in people-basics, it works fine, but then when I go over to people-stats no corresponding record exists and if I try to create one and fill the Foreign Key column with corresponding data, I get this message: "Cannot edit this cell. Details: Error while executing SQL query on database 'People': no such column: people-basics.person" (I think the message is truncated).
The DDL I currently have for my tables (auto-generated by SQLite Studio based on my GUI operations):
CREATE TABLE [people-basics] (
[person-ID] INTEGER PRIMARY KEY AUTOINCREMENT
UNIQUE
NOT NULL,
[person-NAME] TEXT UNIQUE
NOT NULL,
[person-GENDER] TEXT
);
CREATE TABLE [people-stats] (
[person-NAME] TEXT REFERENCES [people-basics] ([person-NAME]),
[person-SIZE] NUMERIC
);
(I've removed the person-ID column from people-stats for now as it seemed like I should only have one foreign key at a time, not sure whether that's true.)
Alright, that was a little silly.
The entire problem was solved by removing hyphens from table names and column names. (So: charBasics instead of char-basics, etc.)
Ah well.

Use ConditionExpression to limit insert when ID doesn't exist in other table

Simple thing. While inserting data to table A I have a HashKey id and additional hash index for column ex_id, which is kind of a foreign key in table B.
When inserting a new data into table A I would like to create an exception whenever data is inserted with value in column ex_id that doesn't have a correspondent entry in table B.
I thought that ConditionExpression is the way to go, but can't make it work - probably missing something obvious. Tried to use contains()...
Any ideas?
As per my knowledge this would not be possible at DynamoDB end because there are no relationship between the tables.
What you can do is that you can have a condition at the application level, which checks on its own and throw an exception before inserting the value in table A. (You can query table B for that "Id" if found then insert else throw exception)
DynamoDB does not natively support any kind of foreign key support, everything works on a per table basis, per key basis. DynamoDB's approach is to handle such logic at the client level. For example see the dynamodb transactions client. This library allows you to perform transactions across tables which either all succeed or all rollback.
For your case, I would first make a getItem request to table B (use consistent read) if it exists then write to table A.
Then I would enable streams on table A and write a lambda function to check if any data violations get written to the table.

insert data from a asp.net form to a sql database with foreign key constraints

i have two tables
asset employee
assetid-pk empid-pk
empid-fk
now, i have a form to populate the asset table but it cant because of the foreign key constraint..
what to do?
thx
Tk
Foreign keys are created for a good reason - to prevent orphan rows at a minimum. Create the corresponding parent and then use the appropriate value as the foreign key value on the child table.
You should think about this update as a series of SQL statements, not just one statement. You'll process the statements in order of dependency, see example.
Asset
PK AssetID
AssetName
FK EmployeeID
etc...
Employee
PK EmployeeID
EmployeeName
etc...
If you want to "add" a new asset, you'll first need to know which employee it will be assigned to. If it will be assigned to a new employee, you'll need to add them first.
Here is an example of adding a asset named 'BOOK' for a new employee named 'Zach'.
DECLARE #EmployeeFK AS INT;
INSERT (EmployeeName) VALUES ('Zach') INTO EMPLOYEE;
SELECT #EmployeeFK = ##IDENTITY;
INSERT (AssetName, EmployeeID) VALUES ('BOOK',#EmployeeFK) INTO ASSET;
The important thing to notice above, is that we grab the new identity (aka: EmployeeID) assigned to 'Zach', so we can use it when we add the new asset.
If I understand you correctly, are you trying to build the data graph locally before persisting to the data? That is, create the parent and child records within the application and persist it all at once?
There are a couple approaches to this. One approach people take is to use GUIDs as the unique identifiers for the data. That way you don't need to get the next ID from the database, you can just create the graph locally and persist the whole thing. There's been a debate on this approach between software and database for a long time, because while it makes a lot of sense in many ways (hit the database less often, maintain relationships before persisting, uniquely identify data across systems) it turns out to be a significant resource hit on the database.
Another approach is to use an ORM that will handle the persistence mapping for you. Something like NHibernate, for example. You would create your parent object and the child objects would just be properties on that. They wouldn't have any concept of foreign keys and IDs and such, they'd just be objects in code related by being set as properties on each other (such as a "blog post" object with a generic collection of "comment" objects, etc.). This graph would be handed off to the ORM which would use its knowledge of the mapping between the objects and the persistence to send it off to the database in the correct order, perhaps giving back the same object but with ID numbers populated.
Or is this not what you're asking? It's a little unclear, to be honest.

Should I use an auto-generated Primary Key if I'm just doing a lookup table?

I have a table which has two varchar(Max) columns
Column 1 Column 2
-----------------------
URLRewitten OriginalURL
its part of my url re-writing for an asp.net webforms site.
when a url comes in I do a check to see if its in the table if it is i use the OriginalURL.
My question is, if all I'm doing is querying the table for urls and no other table in the database will ever link to this table does it need a dedicated primary key field? like an auto-number? will this make queries faster?
and also how can I make the query's run as faster?
Edit: I do have a unique constraint on URLRewitten.
Edit: ways i'm using this table..
Query when a new Request comes in.. search on URLRewitten to find OriginalURL
When needing to display a link on the site, i query on the OriginalURL to find the URLRewitten url i should use.
When adding a new url to the table i make sure that it doesn't already exist.
thats all the querys i do.. at the moment.
Both columns together would be unique.
Do you need a primary key? Yes. Always. However, it looks like in your case OriginalURL could be your primary key (I'm assuming that there wouldn't be more than one value for URLRewritten for a given value in OriginalURL).
This is what's known as a "natural key" (where a component of the data itself is, by its nature, unique). These can be convenient, though I have found that they're generally more trouble than they're worth under most circumstances, so yes, I would recommend some sort of opaque key (meaning a key that has no relation to the data in the row, other than to identify a single row). Whether or not you want an autonumber is up to you. It's certainly convenient, though identity columns come with their own set of advantages and disadvantages.
For now I suppose I would advise creating two things:
A primary key on your table of an identity column
A unique constraint on OriginalURL to enforce data integrity.
I'd put one in there anyway... it'll make updating alot easier or duplicating an existing rule...
i.e. this is easier
UPDATE Rules SET OriginalURL = 'http://www.domain.com' WHERE ID = 1
--OR
INSERT INTO Rules SELECT OriginalUrl, NewUrl FROM Rules WHERE ID = 1
Than this
this is easier
UPDATE Rules SET OriginalURL = "http://www.domain.com" WHERE OriginalURL = 'http://old.domain.com'
--OR
INSERT INTO Rules SELECT OriginalUrl, NewUrl FROM Rules WHERE OriginalURL = 'http://old.domain.com'
In terms of performance, if your going to be searching by OriginalURL,
you should add an index to that column,
I would use the OriginalURL as your primary key as I would assume this is unique. Assuming your are using SQL-Server you could create an index on RewrittenURL with OrigionalURL as an "Included column" to speed up the performance of the query.
An identity column can help when you search for recent events:
select top 100 * from table order by idcolumn desc
We'd have to know what kind of queries you are running, before we can search for a way to make them faster.
As you are doing your query on the URLRewritten column I don't think adding an auto-generated primary key would help you.
Have you got an index on your URLRewritten column? If not, create one: that should see a big increase in the speed of your queries (perhaps just make URLRewritten your primay key?).
Yes there should be a Primary Key Because you can set INDEX on that Primary Key for Fast Access
I don't think adding auto generated primary key will make your query faster.
However there are are a few things to consider:
I would not be so sure, that never
ever nothing will link to this table
:(.
I've seen a lot of people asking about
how to i.e. remove duplicates from
table like that -- with primary key
it is much easier.
To make this query
faster we need to
know more about this table and ways
of using it...
In my opinion, every table, must have auto generated primary key (i.e. identity in MSSQL).
I don't believe in unique natural keys.

Resources