I'm using Oracle APEX 4.2.6 and Oracle DB 11gR2
I've an interactive report showing the list of clients.
The end user can modify the Name of the client.
My issue is that I have to find a way to allow the end user to find the modified client by seraching it with his old name.
For example, the end user modify the name of client from OLD NAME to NEW NAME
In the serach engine of the interactive report, the end users must be able to find the client by serching it by its old name OLD NAME
Is there a way to manage this situation on the APEX side or Database side.
This is very much a database issue, not an APEX issue. When the user modifies the client name, you will need to record the old name somewhere: this could simply be an OLD_NAME column on the CLIENTS table (which would only support knowing the previous name for a single name change), or it could be a CLIENT_NAME_HISTORY table to which a row is added every time a client name is changed.
Having done that, your interactive report's SQL can then be modified to search both old and new names to find the client - for example:
select ...
from clients
where (name like :P1_NAME or old_name like :P1_NAME)
or
select ...
from clients c
where (c.name like :P1_NAME or exists (select null
from client_name_history h
where h.client_id = c.client_id
and h.name like :P1_NAME)
Note that I think you will need to create a page item for the name filter, because the built-in filter of the IR can only search data that is displayed in the report, which previous names will not be (presumably).
Having additional columns might not be a "scalable" solution. What if another user changes the name again? And again? And again?
A better approach to store this data would be in rows that are uniquely identified by a combination of the primary key of the client along with an object version identifier - this could be a number or a time stamp or a date range. This is an approach that Oracle themselves use in many of its enterprise application.
Example of the data would look like below.
1.) Using Object Version Number
Client Id | Client Name | Object Version Number
1 | Bob | 1
1 | Sam | 2
1 | Ed | 3
Here, every time a user changes the name an additional row is created maintaining the same client_id value but incrementing the object version number by 1. The highest ovn represents the latest value. You could also have a column called "latest_record" and insert a value of Y when creating a new record to show that this is the latest record (resetting the value in the previous latest record to N). Similarly, instead of a number, you can simply store the timestamp and use that to determine the latest record.
Using date range
Client Id | Client Name | Start Date | End Date
1 | Bob | 01-Jan-2017 | 31-Jan-2017
1 | Sam | 02-Feb-2017 | 02-Mar-2017
1 | Ed | 03-Mar-2017 |
In this approach, you are specifying the period of time for which the name was valid. A use case would be an individual taking the adopting the surname of their partner after marriage. In such a case, one name was valid from the time of birth to the date of marriage and another name was valid from the date of marriage onwards.
Once you prepare your datastructure in this format, in the apex report you just need to query on the single name column. I feel additional tables and columns are an unnecessary overhead in this case.
Regards,
SJ
Related
I've see older posts around this but hoping to bring this topic up again. I have a table in DynamoDB that has a UUID for the primary key and I created a secondary global index (SGI) for a more business-friendly key. For example:
| account_id | email | first_name | last_name |
|------------ |---------------- |----------- |---------- |
| 4f9cb231... | linda#gmail.com | Linda | James |
| a0302e59... | bruce#gmail.com | Bruce | Thomas |
| 3e0c1dde... | harry#gmail.com | Harry | Styles |
If account_id is my primary key and email is my SGI, how do I query the table to get accounts with email in ('linda#gmail.com', 'harry#gmail.com')? I looked at the IN conditional expression but it doesn't appear to work with SGI. I'm using the go SDK v2 library but will take any guidance. Thanks.
Short answer, you can't.
DDB is designed to return a single item, via GetItem(), or a set of related items, via Query(). Related meaning that you're using a composite primary key (hash key & sort key) and the related items all have the same hash key (aka partition key).
Another way to think of it, you can't Query() a DDB Table/index. You can only Query() a specific partition in a table or index.
Scan() is the only operation that works across partitions in one shot. But scanning is very inefficient and costly since it reads the entire table every time.
You'll need to issue a GetItem() for every email you want returned.
Luckily, DDB now offers BatchGetItem() with will allow you to send multiple, up to 100, GetItem() requests in a single call. Saves a little bit of network time and automatically runs the requests in parallel; but otherwise is the little different from what your application could do itself directly with GetItem(). Make no mistake, BatchGetItem() is making individual GetItem() requests behind the scenes. In fact, the requests in a BatchGetItem() don't even have to be against the same tables/indexes. The cost for each request in a batch will be the same as if you'd used GetItem() directly.
One difference to make note of, BatchGetItem() can only return 16MB of data. So if your DDB items are large, you may not get as many returned as your requested.
For example, if you ask to retrieve 100 items, but each individual
item is 300 KB in size, the system returns 52 items (so as not to
exceed the 16 MB limit). It also returns an appropriate
UnprocessedKeys value so you can get the next page of results. If
desired, your application can include its own logic to assemble the
pages of results into one dataset.
Because you have a GSI with PK of email (from what I understand) you can use PartiQL command to get your batch of emails back. The API is called ExecuteStatment and you use a SQL like syntax:
SELECT * FROM mytable.myindex WHERE email IN ['email#email.com','email1#email.com']
I have an existing sqlite database with a table in it something like this:
+------+----------+--------------------+----------------+
|LogID | UsedOn | UserID | Other fields() |
+------+----------+--------------------+----------------+
| 1 | | soemid03 | SomeDataHere |
+------+----------+--------------------+----------------+
Etc....
The UsedOn field is currently blank, because when I made the table I accidently forgot to set the field type to a timestamp type, so the application was just inserting the other colums and leaving this one blank.
Because I would like to use a comparison at some point later using the timestamp, I would like to update this column for all rows in the table with the current timestamp, I assume I can use datetime() in sqlite to do this. It does not matter too much that some of the dates and times will be out by a few days, but the field cannot be empty or my comparison code would not work.
I tried using:
UPDATE tablename SET UsedOn=datetime()
And this was accepted as a valid query, but it seems to do nothing, this column is still empty.
perhaps I'm doing this wrong in some way?
I can only edit the database/table via either manual queries or by using 'SQLite Administrator' app (from http://sqliteadmin.orbmu2k.de/). I can't use anything else because that is what is available and I'm not allowed to install any other database management tools. When I try to edit any row in the table to add a datetime manually, it does not get accepted, but I just assume this is because the app is trying to insert what I type as a string (even though the format is correct) and it's not a string field type.
I tried your code in SQLite Administrator and it does not work, while it should.
What does work is:
UPDATE tablename
SET UsedOn = CURRENT_TIMESTAMP
This does not mean that your code is wrong.
If you use any other tool like DB Browser for SQLite, both solutions would work.
I am using sqlite as my database. It is connected to the livecode project.
The Contacts table has the following data (address and contact number are omitted for security)
ID Name Address Contact No.
1 John ...Philippines 0999999999
2 Kim ...Philippines 0999999999
When I executed this command...
SELECT Name from Contacts ORDER BY ID DESC LIMIT 1
It will return
Kim
In Livecode, I want to store that value to the variable and display it as a Message Box.
How to do that?
You can use any of LiveCodes database functions. First you need to open the database via:
revOpenDatabase("sqlite",filepath[,sqliteOptions])
Then you can query the database via one of the query commands:
revQueryDatabase(databaseID,SQLQuery[,{variablesList | arrayName}])
There is also a function called revDataFromQuery([columnDelim],[rowDelim],databaseID,SQLQuery[,varsList]) that you might use for your query.
Look them up in your dictionary and you may also have a look at the "Book Database" provided via the start center.
So using the last function you can use:
put revOpenDatabase("sqlite","/path/to/your/database") into tDB
revDataFromQuery(,,tDB,"SELECT Name from Contacts ORDER BY ID DESC LIMIT 1", tResult)
answer tResult
(Using empty row and column delimiter as you only select one field in one post.)
The architecture for this scenario is as follows:
I have a table of items and several tables of forms. Rather than having the forms own the items, the items own the forms. This is because one item can be on several forms (although only one of each type, but not necessarily on any). The forms and items are all tied together by a common OrderId. This can be represented like so:
OrderItems | Form A | Form B etc....
---------- |--------- |
ItemId |FormAId |
OrderId |OrderId |
FormAId |SomeField |
FormBId |OtherVar |
FormCId |etc...
This works just fine for these forms. However, there is another form, (say, FormX) which cannot have an OrderId because it consists of items from multiple orders. OrderItems does contain a column for FormXId as well, but I'm confused about the best way to get a list of the "FormX"s related to a single OrderId. I'm using MySQL and was thinking maybe a stored proc was the best way to go on this, but I've never used a stored proc on MySQL and don't really know the best way to go about it. My other (kludgy) option was to hit the DB twice, first to get all the items that are for the given OrderId that also have a FormXId, and then get all their FormXIds and do a dynamic SELECT statement where I do something like (pseudocode)
SELECT whatever FROM sometable WHERE FormXId=x OR FormXId=y....
Obviously this is less than ideal, but I can't really think of any other way... anything better I could do either programmatically or architecturally? My back-end code is ASP.NET.
Thanks so much!
UPDATE
In response to the request for more info:
Sample input:
OrderId = 1000
Sample output
FormXs:
-----------------
FormXId | FieldA | FieldB | etc
-------------------------------
1003 | value | value | ...
1020 | ... .. ..
1234 | .. . .. . . ...
You see the problem is that FormX doesn't have one single OrderId but is rather a collection of OrderIds. Sometimes multiple items from the same order are on FormX, sometimes it's just one, most orders don't have any items on FormX. But when someone pulls up their order, I need for all the FormXs their items belong on to show up so they can be modified/viewed.
I was thinking of maybe creating a stored proc that does what I said above, run one query to pull down all the related OrderIds and then another to return the appropriate FormXs. But there has to be a better way...
I understand you need to get a list of the "FormX"s related to a single OrderId. You say, that OrderItems does contain a column for FormXId.
You can issue the following query:
select
FormX.*
From
OrderItems
join
Formx
on
OrderItems.FormXId = FormX.FormXId
where
OrderItems.OrderId = #orderId
You need to pass #orderId to your query and you will get a record set with FormX records related to this order.
You can either package this query up as a stored procedure using #orderId paramter, or you can use dynamic sql and substitute #orderId with real order number you executing your query for.
I'm new to ASP.NET but not to programming. I am migrating our current site from PHP/MySQL to ASP.NET(3.5)/SqlServer. I've been lurking here since the site's launch, so I'm confident that one (or more) of you can help me out. Here's the scenario:
This is a training department site and the dept. has a course catalog stored in the table course. Each course may have many prerequisite courses, For example, A and B are prerequisites for C. I would normally store this either as a comma-delimited column in course or in a separate table course_prereq or course_course as a recursive relationship. This part I can do.
However, the business rules require that each course can have multiple sets of prerequisites. Fore example, N requires A, B and C, or N requires X and Y. This is where I'm stuck.
Previously, I stored this information in a column for row N as A,B,C|X,Y, parsed the ids into a PHP 2D-array, submitted a second query for all the rows whose id was in that array, then used PHP to separate those rows into their respective groups. Once all this processing is done, the groups of prerequisites are displayed as separate tables on the web page, like so:
| A | A's information goes here |
| B | B's information goes here |
| C | C's information goes here |
- - - - - - - OR - - - - - - - -
| X | X's information goes here |
| Y | Y's information goes here |
How would I accomplish this using ASP.NET?
Add a table to hold Prerequisite Sets. This table holds a set ID and key back to the courses table for each course in the set. The table may have several rows for a given set ID, so your primary key will be the set ID plus the course ID. Then in your course_prereq table you relate courses to the different prerequisite sets. An OR relationship can be assumed there because any ANDs are enforced in the sets themsevles.
Have a table called PrerequisiteSet that FKs to each prereq. Then have a Course_PrerequisiteSet many to many table that FKs to Course and PrerequisiteSet. Most of the time there will only be one entry in Course_PrerequistieSet, but if there are more than one, then it will be an OR relationship.
Both the answers above were very helpful. I ended up using just one database table instead of the suggested two. The table contains a course_id, prereq_id, and set_id, which all together form the primary key.
In the ASP.NET page, I use a repeater to loop over the sqldatasource stored procedure that returns a course's prerequisite sets, and a gridview inside that repeater that reads the individual prerequisite information from a second sqldatasource stored procedure. Like this:
RepeaterSqlDataSource (returns set ids)
Repeater
. . . GridViewSqlDataSource (returns course info for each prereq_id in set
. . . GridView
Hope this is helpful to anyone else looking at a similar scenario.