very simple sql select into a cursor has never worked for me - visual-foxpro

Been writing foxpro since 2.6 so 40 years. Never been able to get this to work. for umpteenth time searched web for hours but no luck. HELP!
Select * from mytable into cursor mycursor1
select * from mycursor1 into cursor mycursor2
results:
mycursor1 contains the data from mytable as it should.
mycursor2 gets created (all the columns are there) but contains no data. it is always empty.
As I said in my comment, the above DOES work if done from native VFP command window. Here is pseudocode for what does NOT work. I use the VFE framework.
Create a view named mycursor1
This view is never queried. It is semi permanent meaning it is created when the user comes into my Point-Of-Sale screen and released when they leave. While in the POS screens the contents of this view is displayed in a grid. As items are sold I use VFE business objects to add the items to this view and they are shown in that grid. When the user finishes ringing up a sale, I loop thru the view moving the contents of the view to another view (basically scan...replace statements...endscan but I do that with VFE business object commands). Then the data is saved from that 2nd view. Mycursor1 gets emptied (VFE's bo.cancel(.t.) so it is ready to ring up another sale. This part has worked flawlessly for over 30 years and is superfast.
I am inserting some new code just before I move the data from mycursor1 to the 2nd view for saving. That new code does an SQL Select (my database is all native VFP), so Select * from the view named mycursor1 into cursor mycursor2. This where the issue arises. As I said before, I am stepping thru the code. I see the 5 records in mycursor1. Mycursor2 gets created and contains all the fields from mycursor1 but mycursor2 is empty.
I believe this is happening because mycursor1 never get queried and is loaded from code/business objects instead of from VFP via a requery. I am going to do some testing today to see if I can prove that. I will post my results.
Gia has suggested other ways to move the data from mycursor1 to mycursor2. I do not believe that will accomplish my need. Why? I do not need to simply move the data from mycursor1 to mycursor2. When a sale is rang up in my POS screens, it contains rows something like +1 Snickers Bars then +3 Hershey Bars then -1 Snickers Bars, so 3 rows in mycursor1. The reason I am using an SQL select to move the data from mycursor1 to mycursor2 is to use a GROUP BY so that mycursor2 contains the contents of mycursor1 except grouped by item thereby getting rid of the minus (voids). So in this example I would end up with just 1 row in mycursor2 of +3 Hershey Bars. Hope that makes sense.
Thanks, John

In your notes I noticed you were talking about a view. Views are buffered by default and in your case you might have it table buffered. In that case your select from that view wouldn't return any rows, unless you add WITH (BUFFERING=.T.) clause.
Here is a code piece that would simulate what might be happening:
SET MULTILOCKS ON
SELECT * FROM _samples+'data\customer' WHERE .F. INTO CURSOR cursor1 READWRITE
CURSORSETPROP("Buffering",5,'cursor1')
APPEND FROM customer
browse
SELECT * FROM cursor1 INTO CURSOR cursor2 && No rows
*SELECT * FROM cursor1 WITH (buffering=.T.) INTO CURSOR cursor2 && has rows
browse

Related

Showing converted Base64 (from hex) in an existing SQL Server 2019 view

I do voluntary work at an animal shelter. We have an application which uses a SQL Server 2019 database. I have created a view that includes a varbinary(max) column. The value in this column is a picture, stored in hexadecimal-format. I would like to convert this Hex-value to a base64-binary file and add these to the view as an extra column.
I found the perfect solution for my situation in SQL Server : hex to base64. The example provided converts 1 single hex-value into 1 base64-value. I now need to add this solution to my view, but I'm not having any success.
The offered solution:
DECLARE #TestBinHex varchar(max), #TestBinary varbinary(max), #Statement nvarchar(max);
SELECT #TestBinHex = '0x012345';
SELECT #Statement = N'SELECT #binaryResult = ' + #TestBinHex;
EXECUTE sp_executesql #Statement, N'#binaryResult varbinary(max) OUTPUT', #binaryResult=#TestBinary OUTPUT;
SELECT
CAST(N'' AS XML).value(
'xs:base64Binary(xs:hexBinary(sql:column("bin")))'
, 'VARCHAR(MAX)'
) Base64Encoding
FROM
(SELECT #TestBinary AS bin) AS bin_sql_server_temp;
A simplified version of my view:
SELECT
a.cat_id, a.catname, s.cat_id,
s.stay_id, s.shelter_handler, s.shelter_kennel, s.picture
FROM
dbo.animal AS a
OUTER APPLY
(SELECT TOP 1 *
FROM dbo.shelterdata
WHERE a.cat_id = s.cat_id
ORDER BY s.stay_id DESC) AS S
WHERE
(a.cat_id IS NOT NULL) AND (s.leave_date IS NULL)
The view shows an overview of all cats currently present in the shelter (leave_date is NULL). The reason for the TOP 1 is that sometimes shelter animals get returned, and the application then assigns a new stay_id. To prevent duplicate values from the join, I only return the value of the most recent stay_id.
What I am trying to achieve: the second table (dbo.shelterdata) includes the picture, stored in hex value. I'd like to add a column Base64Encoding to the view which includes the converted value.
My attempts
I was successful in replacing the static value '0x012345' by a SELECT statement. But the way the solution is formatted, it only allows for one input value. So I had to restrict it with a WHERE clause. It is obvious to me that I need to make a subquery which inputs the hex value based on the unique cat_id. However, it has been many years since I worked with variable, so I'm struggling with the formatting of the statement.
My request
Does anyone have a suggestion how to build the conversion into the view?
Any assistance would be greatly appreciated.
After searching for a few more hours, I stumbled onto the solution. Maybe it will help someone else in the future. The solution is remarkably simple, as is often the case.
My view, mentioned above, is called dbo.shelter_view
select sv.picture,sv.cat_id,
cast('' as xml).value(
'xs:base64Binary(sql:column("sv.picture"))', 'varchar(max)'
) as Base64Encoding
from dbo.shelter_view as SV

FRM-40501 in oracle forms

from clause query i put a query to get data from two tables check that code
select empno,ename,job,mgr,hiredate,sal,comm,deptno,grade gr
from emp
left outer join salgrade on ( emp.sal between losal and hisal)
i also change the properties to be visible and not visible like that code
if get_item_property('text_item17', visible) = 'TRUE' then
set_item_property('text_item17', visible, property_false);
else
set_item_property('text_item17', visible, property_true);
set_item_property('text_item17',enabled,property_true);
set_item_property('text_item17',enabled,property_true);
set_item_property('text_item17',NAVIGABLE ,property_true);
set_item_property('text_item17',UPDATE_ALLOWED,property_true);
set_item_property('text_item17',QUERYABLE,property_true);
set_item_property('text_item17',UPDATE_NULL,property_true);
end if;
when i run the form i am getting that error that i can't update the data
Forms doesn't know which table those columns belong to, so it can't perform update.
I suggest you create a view, base data block on that view, create an INSTEAD OF trigger which could take care about correct inserting, updating and deleting rows from both tables.
SET_ITEM_PROPERTY calls you posted don't have anything to do with it (i.e. won't solve your problem).
[EDIT]
Saying that you'd want to solve it without a view, I'd suggest you not to spend too much time on that. If you open Online Forms Help and search for "Guidelines for choosing block data sources", you'll see that FROM clause, as a data source, allows query, but does NOT allow DML (inserts, updates and deletes).
from dml data target type choose table and put table name then go to the item text_item17 properties change query only to yes

how to display single record in tabular form?

I want to display single record one by one when button press in tabular form
how to do this in oracle forms?
I'd suggest you to use Forms built-in capabilities and spend time and energy on something else.
i want to display single record when press button single forward and all records when press button double forward
I presume that those buttons ("single" and "double forward") are custom-made buttons (i.e. you created them).
If so, "Double forward" is simple - put EXECUTE_QUERY into its WHEN-BUTTON-PRESSED trigger (assuming that this is a data block, based on a table).
"Single forward" isn't that simple as you can't execute query, so you have to write some code. For example, you could "prepare" result data set into another table, specifying the row number so that you could later use it:
insert into temp_table (rn, deptno, dname, loc)
select rownum, deptno, dname, loc
from dept
where ...
WHERE clause is kind of tricky because user can enter search criteria. How to know it? Use GET_BLOCK_PROPERTY. As it brings scent of dynamic SQL, you'd have to compose the INSERT statement - consider creating a stored procedure which utilizes EXECUTE IMMEDIATE (or, alternatively, see if FORMS_DDL can be used).
As many users can use the same form simultaneously, that "temp table" should be a global temporary table or - if not - you'd have to save user information as well; otherwise, you'll create a chaos.
Suppose data is now prepared. In a form, you'd have to create a parameter (or a global variable) which holds current "row number" (rn) value. "Single forward" button's trigger would then
last_record;
create_record;
select deptno, dname, loc
into :blk.deptno, :blk.dname, :blk.loc
from temp_table where rn = :parameter.rn;
-- prepare the next row
:parameter.rn := :parameter.rn + 1;
OK, now you have your data, and new problems arrive. As it is a data block, inserting values into it in that manner presumes that you inserted brand new set of information, and Forms will treat it like that. So, if you try to save it, you'll get a unique key violation (which is OK) or duplicate data (which is bad).
It means that "data block" should, actually, be a "control block", which isn't related to a table. Furthermore, it means that "Double forward" can't work the way I described, but by modifying "Single forward" button's code (don't fetch row-by-row, but all of them at once).
If it is a control block, now you have to find a way to store modified values as well as newly added records, so you'd have to create your own ON-INSERT, ON-UPDATE, etc. triggers.
Shortly, I don't think that what you want is a simple task. Did I already say that you shouldn't do it in the first place? Well, I still think so.
Hopefully, someone else will have a better, simpler suggestion.

PL/SQL: ORA 01422 fetch returns more than requested number of rows

I am developing an order transaction where a user can order a product. Once they clicked the 'add to cart' button, it will be able to save on the database in how many times they want with the same order id. Order id is like a transaction id.
My problem is that whenever I want to display the items that customer ordered, it displays an error or ORA 01422. How can I resolve this error?
Here is my code
DECLARE
order_item_id NUMBER;
BEGIN
order_item_id := :MOTOR_PRODUCTS_ORDER.M_ORDERID;
SELECT MOTOR_ID,
MOTOR_QTY_PURCHASED,
UNITPRICE
INTO :MOTOR_ORDER_ITEMS.MOTOR_ID,
:MOTOR_ORDER_ITEMS.MOTOR_QTY_PURCHASED,
:MOTOR_ORDER_ITEMS.UNITPRICE
FROM MOTOR_ORDERS
WHERE motor_order_id = order_item_id;
END;
As krokodilo says, this error is caused because your query returns multiple rows. Depending on what you want to do, you have a couple of options.
If you want multiple values then either use a loop and process them one row at a time (if you are going to be performing a dml operation use bulk collect). If you only want a single row then narrow your result set down with an extra where clause, or use MAX to ensure you only get one value back.
If there is more than one row which will be returned from a query you'll need to use a cursor. One way to do this is with a cursor FOR loop:
DECLARE
order_item_id NUMBER;
BEGIN
order_item_id := :MOTOR_PRODUCTS_ORDER.M_ORDERID;
FOR aRow IN (SELECT MOTOR_ID, MOTOR_QTY_PURCHASED, UNITPRICE
FROM MOTOR_ORDERS
WHERE motor_order_id = order_item_id)
LOOP
-- Do something here with the values in 'aRow'. For example, you
-- might print them out:
DBMS_OUTPUT.PUT_LINE('MOTOR_ID=' || aRow.MOTOR_ID ||
' MOTOR_QTY_PURCHASED=' || aRow.MOTOR_QTY_PURCHASED ||
' UNITPRICE=' || aRow.UNITPRICE);
END LOOP;
END;
Best of luck.
This looks like a Forms question; is it? If so, my suggestion is to let Forms do that job for you.
According to what you posted, there are two blocks:
MOTOR_PRODUCTS_ORDER (a master block, form type)
MOTOR_ORDER_ITEMS (a detail block, tabular type)
I guess that there is a master-detail relationship between them. If there's none, I'd suggest you to create it. Although you can make it work without such a relationship, it'll be much more difficult. If you are unsure of how to do it, start from scratch:
delete MOTOR_ORDER_ITEMS block (detail)
create it once again, this time by following the Data Block Wizard
Set MOTOR_PRODUCTS_ORDER to be its master block
Relationship is on ORDER_ID column/item
Let's presume that by this point everything is set up. Retrieving items that belong to that ORDER_ID is now very simple:
navigate to master block
enter query mode
enter value into an item that represents ORDER_ID
execute query
End of story. Forms triggers & procedures (which were created by the Wizard) will do its job and retrieve both master and detail records.
No need for additional coding; if you're skilled developer, you can create such a form in a matter of minutes. Won't be beautiful, but will be effective & reliable.
There's really no use in doing it manually, although it is possible. Your code works if there's a single item for that ORDER_ID. For two or more items, as you already know, it'll fail with TOO-MANY-ROWS error.
Basically, if you insist, you should use a loop:
you'd enter ORDER_ID into the master block
as you need to move through the detail block, i.e. use NEXT_RECORD, which is a restricted procedure, you can't use number of triggers (open Forms Online Help System and read about them) so a "Show items" button (with its WHEN-BUTTON-PRESSED trigger) might be just fine
a cursor FOR loop would be your choice
for every row it fetches, you'd populate block items and
navigate to next record (otherwise, you'd keep overwriting existing values in the 1st tabular block row)
As I said: possible, but not recommended.

Oracle querying view

I am having a problem with a simple query of a view. The view itself is nasty having union_all and most of its fields evaluated by functions. The problem is that even a very simple query can get the whole view evaluated which then takes forever.
To simplify my problem I have made this two queries
select * from horrible_view where id in (1, 2, 3); -- this works super quick
select * from horrible_view where id in (select id from my_temp_table); -- this takes forever
select * from my_temp_table t left join horrible_view h on t.id=h.id -- this also takes forever
So even though my_temp_table contains the same 1, 2, 3 (3 rows with just one column) the second and third query makes the optimizer go bananas, so that the horrible view is evaluated completly and then returns just the 3 rows are returned.
Is there anything I could do?
IE in the second example make optimizer run the "select id from my_temp_table" first and then the query.
Oracle's version is 11.2
Further info:
First off I know only a little about Oracle. (So is the Explain plan from sqlDeveloper the thing you want? If so how can you print it, its huge?) Well here is the screenshot: here
I have created the temp table just in order to test. Its actually named TMP_R (and it has 10 rows)

Resources