Update table date field from other table when not null - sql-scripts

I want to update a Date filed for Entry type = 4 )in the table from some records (entry type = 1) in the same table however getting a cannot insert null data into the field error.
UPDATE [Item Ledger Entry]
SET [Last Invoice Date] = (Select MAX([Posting Date])
from [Item Ledger Entry] ILE2
where ILE2.[Item No_] = ILE1.[Item No_] AND
ILE2.[Posting Date] <= ILE1.[Posting Date] AND
ILE2.[Entry Type] = 1 AND
ILE2.[Posting Date] is not null
)
FROM [Item Ledger Entry] ILE1
where ILE1.[Entry Type] = 4

Related

Query filtering based on dates using FMDB?

How do I query games that are after a "visible" date?
The dateformat is set:
FMDatabase *db = self.database;
if([self.database open]){
[db beginTransaction];
NSDateFormatter *formatter = [NSDateFormatter new];
[formatter setDateFormat:#"yyyy-dd-MM'T'HH:mm:ss'Z'"];
[db setDateFormat:formatter];
...
}
The table is created the following way:
[db executeUpdate:#"CREATE TABLE IF NOT EXISTS game (gameId Varchar(36) NOT NULL PRIMARY KEY,name TEXT,visibleFrom TEXT)"];
The query is executed the following way:
FMResultSet *results = [db executeQuery:#"SELECT * FROM game WHERE game.visibleFrom >= ?,[NSDate date]];
This returns nothing. When I use select * from game then i get all the games. But I need the filtered result. Thanks in advance.
Take a look at the SQLite syntax for querying dates: sqlite select with condition on date
You might need something like '#" ... where date > date(?)", formattedDate', where formattedDate is formatted like '1980-12-31'

Objective-c: Most efficient way to get the shortest range from a collection (NSArray) with ranges

I have an NSArray that contains multiple objects which in itself have date ranges NSDate *start and NSDate *end.
What I want to do is to iterate through this array to find the shortest range (between Start and End), based on the current date. Something like this:
Date range Start 1 >----------< Date range End 1
Date range Start 2 >-< Date range End 2
|
Current date
In the example above I would like to get the object that contains Date range start 2 and Date range End 2.
Any ideas and suggestions on how to achieve this?
Update
With based on current date I mean that the current date should be somewhere inside the range. I don't want a range that has an end date that is before the current date, nor a range that has a start date that is in the future.
There are a couple options, depending on how in depth you want the results to be. The first (and easiest) way would be to sort the array by smallest date range:
array = array1 sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
double a = [obj1.endDate timeIntervalSinceDate:obj1.startDate];
double b = [obj2.endDate timeIntervalSinceDate:obj2.startDate];
if ( a < b ) {
return (NSComparisonResult)NSOrderedAscending;
} else if ( a > b ) {
return (NSComparisonResult)NSOrderedDescending;
} else {
return (NSComparisonResult)NSOrderedSame;
}
}
Then when you need to check for the shortest one containing today's date you can just start at the beginning of the array and check if the startdate is before now and the enddate is after now. The first object that matches that criteria is your smallest range around today.
NSDate *date = [NSDate date];
Object *foundObject;
for(Object *obj in array)
{
if([obj.startDate timeIntervalSinceDate:date] <= 0 && [obj.endDate timeIntervalSinceDate:date] >= 0)
{
foundObject = obj;
break;
}
}
If you want to go more in depth you can use a predicate to get a filtered array of all objects that surround today's date. then you can get the shortest range and every other range that includes the date you are looking for.
NSPredicate *pred = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
if([evaluatedObject.startDate timeIntervalSinceDate:date] <= 0 && [evaluatedObject.endDate timeIntervalSinceDate:date] >= 0)
{
return true;
}
return false;
}];
NSArray *array = [array1 filteredArrayUsingPredicate:pred];
I think, this should be a good start point, but I can't provide working code since there is no clear definition, so:
// Result with minimum range
// Assuming that DateRangeObject has start and end properties of NSDate
DateRangeObject *result = nil;
// Array containing DateRangeObject objects
NSArray *arr /* = TODO: provide the content for an array */;
if (arr.count) { /* only if the array contains something */
// Initial result
result = arr[0];
double minTS = DBL_MAX; // max double value, not zero ;) lol
for (DateRangeObject *dro in arr) {
// Get the timestamps for start and end;
double tss = [dro.start timeIntervalSince1970];
double tse = [dro.end timeIntervalSince1970];
// Difference between end and start (positive value)
double diff = tse - tsa;
if (minTS < diff) {
minTS = diff;
// Current minimum
result = dro;
}
}
}

FMDB sqlite's sql query not working

I am creating a temp table using the following SQL query. But its not showing any results (result set is empty) when I execute it programmatically, and shows records when I execute it manually on the database.
NSString *query=[NSString stringWithFormat:#"create temp table search2 as select Observationsid from Observations where admin_id=%d AND teacher_id=%d AND observation_type=%d AND isvalid='yes' AND date BETWEEN '12-20-2013' AND '12-23-2013'",appDelegate.admin_id,appDelegate.teacher_id,appDelegate.observationType];
FMResultSet *results=[appDelegate.database executeQuery:query];
Nslogged query:
Printing description of results->_query:
create temp table search2 as select Observationsid from Observations where admin_id=2 AND teacher_id=1 AND observation_type=2 AND isvalid='yes' AND date BETWEEN '12-20-2013' AND '12-23-2013'
and records are there in database.
This SQL statement shouldn't return results, so you should use executeUpdate method rather than a executeQuery method. You should not see any results from this. If you want to see the results, do a separate executeQuery statement returning the results from search2. (I assume you're building the search2 table for a reason.)
NSString *query=[NSString stringWithFormat:#"create temp table search2 as select Observationsid from Observations where admin_id=%d AND teacher_id=%d AND observation_type=%d AND isvalid='yes' AND date BETWEEN '12-20-2013' AND '12-23-2013'",appDelegate.admin_id,appDelegate.teacher_id,appDelegate.observationType];
if (![appDelegate.database executeUpdate:query])
NSLog(#"create error: %#", [appDelegate.database lastErrorMessage]);
query = #"SELECT * FROM search2";
FMResultSet *results = [appDelegate.database executeQuery:query];
if (!results)
NSLog(#"create error: %#", [appDelegate.database lastErrorMessage]);
By the way, while you can get away with stringWithFormat for this particular SQL, that's not a good idea. You generally want to use the ? placeholders, e.g.
NSString *query = #"create temp table search2 as select Observationsid from Observations where admin_id=? AND teacher_id=? AND observation_type=? AND isvalid='yes' AND date BETWEEN '12-20-2013' AND '12-23-2013'";
if (![appDelegate.database executeUpdate:query, #(appDelegate.admin_id), #(appDelegate.teacher_id), #(appDelegate.observationType)])
NSLog(#"create error: %#", [appDelegate.database lastErrorMessage]);
Unrelated, but I notice that you're using MM-DD-YYYY format text string for your dates. That's not going to work. SQLite doesn't natively "understand" dates. Notably, if you've stored your dates in MM-DD-YYYY format, a text string of 12-21-2052 is BETWEEN '12-20-2013' AND '12-23-2013' (because text strings are compared in alphabetically order), which is probably not what you intended. See Date And Time Functions.
But, fortunately, FMDB does the NSDate conversion for you, storing it as numeric value. So, for example, let's assume your table was defined as follows:
CREATE TABLE IF NOT EXISTS Observations
(Observationsid INTEGER PRIMARY KEY AUTOINCREMENT,
admin_id INTEGER,
teacher_id INTEGER,
observation_type INTEGER,
isvalid TEXT,
date REAL);
You really want to use YYYY-MM-DD or, better, rely upon FMDatabase to convert your NSDate values for you. Remember, SQLite does not have proper date formats, so choose an appropriate format (e.g. YYYY-MM-DD format) or let FMDatabase handle this for you, using NSDate objects.
If you want to facilitate the conversion of date strings to dates, you can use a NSDateFormatter, e.g.:
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = #"MM-dd-yyyy";
NSDate *someDate = [formatter dateFromString:#"12-22-2013"];
if (![appDelegate.database executeUpdate:#"INSERT INTO Observations (admin_id, teacher_id, observation_type, isvalid, date) VALUES (?, ?, ?, ?, ?)", #(appDelegate.admin_id), #(appDelegate.teacher_id), #(appDelegate.observationType), #"yes", someDate])
NSLog(#"insert error: %#", [appDelegate.database lastErrorMessage]);
Or, if I wanted to select the dates between these two dates:
NSDate *startDate = [formatter dateFromString:#"12-20-2013"];
NSDate *endDate = [formatter dateFromString:#"12-23-2013"];
NSString *query = #"create temp table search2 as select Observationsid, date from Observations where admin_id=? AND teacher_id=? AND observation_type=? AND isvalid='yes' AND date BETWEEN ? AND ?";
if (![appDelegate.database executeUpdate:query, #(appDelegate.admin_id), #(appDelegate.teacher_id), #(appDelegate.observationType), startDate, endDate])
NSLog(#"create error: %#", [appDelegate.database lastErrorMessage]);
query = #"SELECT * FROM search2";
FMResultSet *results = [appDelegate.database executeQuery:query];
if (!results)
NSLog(#"select error: %#", [appDelegate.database lastErrorMessage]);
while ([results next])
NSLog(#"%d %#", [results intForColumnIndex:0], [results dateForColumnIndex:1]);
If you want to avoid this NSDate logic, you could alternatively consciously store dates in a text format in YYYY-MM-DD format. That works, too. Again, see that Date and Time Functions page for a list of valid text formats for dates.

iOS sqlite3_step hold / freeze after last row data

My sqlite3_step holds for a 1s after read of last row data. Why?
-(NSDictionary*)specificationItemsForConfigurationsIds:(NSString*)configurationsIdsStr
{
[self databaseOpen];
NSString *query = [NSString stringWithFormat:#"SELECT SpecItem.id,SpecItem.name,ConfigurationSpec.configuration_id\
FROM (SpecItem INNER JOIN ConfigurationSpec ON ConfigurationSpec.spec_item_id=SpecItem.id)\
WHERE (SpecItem.parent_id=12 OR SpecItem.parent_id=34 OR SpecItem.id=23 OR SpecItem.id=27) AND ConfigurationSpec.configuration_id IN (%#)",configurationsIdsStr];
sqlite3_stmt *statement;
NSMutableDictionary* configurationsWithSpecItems = [NSMutableDictionary new];
if (sqlite3_prepare_v2(database, [query UTF8String], -1, &statement, nil) == SQLITE_OK)
{
while (sqlite3_step(statement) == SQLITE_ROW)
{
int specItemId = sqlite3_column_int(statement, 0);
NSString* specItemName = [self sqlite3_column_text_asString_ofStatement:statement
atColumn:1];
int configId = sqlite3_column_int(statement, 2);
NSString* configIdNumber = [NSString stringWithFormat:#"%d",configId];
NSMutableArray* specItems = [configurationsWithSpecItems objectForKey:configIdNumber];
if(specItems == nil)
{
specItems = [NSMutableArray new];
[configurationsWithSpecItems setObject:specItems
forKey:configIdNumber];
}
SpecificationItem* specItem = [SpecificationItem specificationItemWithId:specItemId
name:specItemName];
[specItems addObject:specItem];
// When we read last row data, getting from here to POINT 2 takes 1s
}
// POINT 2
sqlite3_finalize(statement);
}
[self databaseClose];
return configurationsWithSpecItems;
}
Single read of one row takes 2-3ms, but after last one getting out of while loop takes 1s, which is too much for me.
EXPLAIN QUERY PLAN output for this query:
0 0 1 SCAN TABLE Configuration (~100000 rows)
0 0 0 EXECUTE LIST SUBQUERY 1
1 0 0 SEARCH TABLE Configuration USING AUTOMATIC COVERING INDEX (model_id=?) (~7 rows)
0 1 0 SEARCH TABLE SpecItem USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)
There are two explanations for the delay; one or both might apply:
All the records that match are at the beginning of the Configuration table. After the last matching record, SQLite still has to search through all the remaining records, but none matches.
SQLite creates a temporary index on the model_id column because it estimates that the query would be even slower without it. After the query has finished, that index must be deleted again; what you see is the time needed to synchronize at the end of the (automatic) transaction.
Create an index on the model_id column will help avoiding both of these points.
If possible, you should try to merge the subquery (in configurationsIdStr) into the outer query; instead of:
... ConfigurationSpec.configuration_id IN (
SELECT configuration_id FROM Configuration WHERE model_id = 42)
use something like this:
... ConfigurationSpec.model_id = 42
Avoiding that indirection makes it much easier for SQLite to optimize the query execution.

Rows order in SQLite Database (iOS)

I have a database with a table called 'connection', for simplicities' sake, let's say I only have one column which is called 'rowName'. Now let's say I add a row with rowName = a; now I add a row with rowName = q, and lastly I add a row with rowName = w (letters are completely random). Now, I irritate thru the results with the statement:
NSString * queryStatements = [NSString stringWithFormat:#"SELECT rowName, FROM tableName"];
and using the code:
NSMutableArray * rows = [[NSMutableArray alloc] init]; //create a new array
sqlite3_stmt * statement;
if(sqlite3_prepare_v2(databaseHandle, [queryStatements UTF8String], -1, &statement, NULL) == SQLITE_OK){
while (sqlite3_step(statement) == SQLITE_ROW){
NSString * rowName = [NSString stringWithUTF8String : (char*) sqlite_column_text(statement, 1)];
[rows addObject : connection];
} sqlite3_finalize(statement_;
}
In the array rows, will the object at index 0 be rowName = a, and at index 1 rowName=q, and at index 2 rowName = w? or will it be random? Is there a way to make it not-random?
Also, if i delete a row, will it have any affect on the other rows order?
Never depend on a sort order from your database. Always specify one if it is required.
SELECT rowName FROM tableName order by rowName
gives you the data sorted by rowName. If you need a different order, you need another column.
You can also sort your NSArray if need be.
What sort order are you looking for?

Resources