Iterating through a cursor in Sybase ASE seems to do multiple loops - sybase-ase

I am creating a cursor using select statement that would return 4 values (18, 13, 14 and 15). I am trying to iterate through the cursor and display the value for now. I am expecting 4 print statements, but I see lot more than that.
Here is the code:
PRINT '***** *****'
GO
DECLARE curs CURSOR FOR
SELECT ID FROM CUSTOMER WHERE SSN LIKE '%1803'
GO
DECLARE #ID int
OPEN curs
FETCH NEXT curs INTO #ID
WHILE ##sqlstatus = 0
BEGIN
PRINT '* current value: %1! ', #ID
FETCH NEXT curs INTO #ID
END
CLOSE curs
DEALLOCATE CURSOR curs
GO
Here is the output:
***** *****
* current value: 18
* current value: 18
* current value: 13
* current value: 18
* current value: 13
* current value: 14
* current value: 18
* current value: 13
* current value: 14
* current value: 15
* current value: 18
* current value: 13
* current value: 14
* current value: 15
It seems like a simple iterate over cursor and I cannot understand why I am seeing so many print statements, I want to only see 18, 13, 14 and 15. I am using Sybase ASE 15.5 and Razor SQL client. Can someone help me with this?
* Edit *
I didn't see the issue when I used Sybase Central (for ASE). The results were inconsistent when I used other IDEs.

Firstly make sure you always use an order by with any SQL nowadays to ensure you get data back in the order you expect. You don't know how the database will optimise the query at the backend so be specific.
Also check a direct select and check how many rows match for 'SSN LIKE '%1803' to begin with to cross-check the rowcounts against the cursor.

Related

parsing data from one table to another table

I am trying to write a query to copy data from one table to another table in PL/SQL and I need help, thanks.
Source table has single field and destination has 3 fields.
Data in the source table starts with 05, 10, 30 1nd 99 as below
05-1
10-1
30-1
10-2
30-2
30-2
30-2
30-2
10-3
30-3
99-1
05-2
10-4
30-4
need to copy data into another table with 3 columns as below
A B C
05-1 10-1 30-1
05-1 10-2 30-2
05-1 10-2 30-2
05-1 10-2 30-2
05-1 10-2 30-2
05-1 10-3 30-3
05-2 10-4 30-4
Your question is not clear but at a guess from the input and output you have provided I am assuming that the rules to generate the output are somthing along the lines of the below.
1) when it starts with 99 ignore it
2) when it starts with 05 set variable and move on to next row.
3) when it starts with 10 set variable and move on to next row.
4) when it starts with 30 insert into tables using the variables you have set in previous 2 steps.
If the above rules are correct the below should work. Of course you will need to substitute in your table / field names. If I have misunderstood your requirements from the data provided (quite likely as it is not very clear), this should at least give you a starting point to work from.
declare
cursor c_loops is
select column1 from table1;
v_col1 varchar2(10) default null;
v_col2 varchar2(10) default null;
v_col3 varcahr2(10) default null;
begin
for v_row in c_loops loop
case (substr(v_row.column1, 0, 2)
when '99' then
-- do nothing ignore row
null;
when '05' then
v_col1 := v_row.column1;
when '10' then
v_col2 := v_row.column1;
when '30' then
v_col3 := v_row.column1;
insert into table2 (col1, col2, col3) values (v_col1, v_col2, v_col3);
else
-- output some error here because you have unexpected input
null;
end case;
end loop;
end;

SSRS parameters dynamically passed to other reports

I'm using SSRS 2008 R2.
This one is hard to describe. I have a report that has a main report on top and 10 sub reports below it. The main report ranks the top 10 industries by revenue. The sub reports are detailed reports within the ranked industries. But they need to be dynamic. So for August, if the #1 industry is AUTO, the sub-report for AUTO appears in position 1. Then in September, if the #1 industry is RETAIL, the sub-report for RETAIL needs to appear in position 1. For example ...
August -->
MAIN REPORT: 1. AUTO
2. RETAIL
3. FOOD
SUB REPORTS: POS 1=AUTO, POS 2=RETAIL, POS 3=FOOD
September -->
MAIN REPORT: 1. RETAIL
2. FOOD
3. CONSUMER
SUB REPORTS: POS 1=RETAIL, POS 2=FOOD, POS 3=CONSUMER
Note that the sub reports order changes depending on the main report. The sub report accepts the Industry name parameter but I don't know how to dynamically change the parameter.
I tried the CHOOSE function as the value of the Industry parameter and it works if I pass it an explicit string of values. I'd love to be able to pass it an array. I tried passing a dataset name but it just thinks its another string value.
=CHOOSE(1,"AUTO","TRAVEL","FINANCIAL",...)
LOOKUP fails because I can't use a Field in the parameter statement.
Any help is appreciated! Thanks, all!
-- Since I can't upload a picture, I'm going to attempt to build a diagram to show you how this would look. Imagine the SSRS work area. There is a main report and several sub reports. I'm using the dots to simulate spaces. Notice that the order of the sub reports change to match the order of the rank in the main report. So what I need to do is pass the industry parameter from the main to the sub reports dynamically.
Main Report - August
Rank...Industry...Revenue
1........AUTO.........$333
2........RETAIL......$222
3........FOOD........$111
Sub Reports - August
.........AUTO
Rank...COMPANY...Revenue
1........TOYOTA........$555
2........HONDA.........$111
3........LEXUS..........$99
.........RETAIL
Rank...COMPANY...Revenue
1........WALMART........$45
2........TARGET.........$35
3........COSTCO..........$25
.........FOOD
Rank...COMPANY...Revenue
1........KROGER........$888
2........MOMS............$277
3........FOOD CITY....$150
Main Report - September
Rank...Industry...Revenue
1........RETAIL.........$333
2........FOOD..........$222
3........CONSUMER........$111
Sub Reports - September
.........RETAIL
Rank...COMPANY...Revenue
1........TARGET........$555
2........JC PENNY.........$111
3........DILLARDS..........$99
.........FOOD
Rank...COMPANY...Revenue
1........FOOD CITY........$45
2........KROGER.........$35
3........RALPHS..........$25
.........CONSUMER
Rank...COMPANY...Revenue
1........P&G...........$888
2........KIMBERLY............$277
3........J&J..........$150
Create 2 report
1) Main Report
2) Sub Report
Note : Sample Image attached
-- Output
Parameter for Sub Report
Main Report Layout
Subreport Layout
2 Parameter created for Sub Report
Datasource
---------- Data Source for Main Report
IF NOT EXISTS (SELECT * FROM tempdb..sysobjects WHERE id=OBJECT_ID('tempdb..#Main'))
BEGIN
CREATE TABLE #Main
(
[Rank] INT,
Indusry VARCHAR(500),
Revenue INT,
[MONTH] int
)
INSERT INTO #Main VALUES(1,'AUTO',333,8)
INSERT INTO #Main VALUES(2,'RETAIL',222,8)
END
SELECT * FROM #Main
------------------ Data source for Sub Report
DECLARE #Industry VARCHAR(50)
SET #Industry ='Auto'
DECLARE #Month Int
SET #Month =8
IF NOT EXISTS (SELECT * FROM tempdb..sysobjects WHERE id=OBJECT_ID('tempdb..#AUTO'))
BEGIN
CREATE TABLE #AUTO
(
[Rank] INT,
Indusry VARCHAR(500),
Revenue INT,
[MONTH] int
)
INSERT INTO #AUTO VALUES(1,'TOYOTA',34,8)
INSERT INTO #AUTO VALUES(2,'HONDA',44,8)
END
IF NOT EXISTS (SELECT * FROM tempdb..sysobjects WHERE id=OBJECT_ID('tempdb..#RETAIL'))
BEGIN
CREATE TABLE #RETAIL
(
[Rank] INT,
Indusry VARCHAR(500),
Revenue INT,
[MONTH] int
)
INSERT INTO #RETAIL VALUES(1,'WALMART',55,8)
INSERT INTO #RETAIL VALUES(2,'TARGET',44,8)
END
IF #Industry ='Auto'
BEGIN
SELECT * FROM #AUTO WHERE [MONTH] = #Month
END
ELSE IF #Industry ='Auto'
BEGIN
SELECT * FROM #RETAIL WHERE [MONTH] = #Month
END
Note : Base on Condition data will display into sub report.. parameter passed from parent report
I think since you want it be dynamic and you have all the parts in place - the easiest way to do this would be to: Right click in the 'Industry' field in the main table, go to properties, select "Action", click the radio button "Go to Report" - click the expression button and add an IIF or Switch statement..
=IIF(Fields!Industry.Value = "Retail", Retailsubreportname, IIF(Fields!Industry.Value = "Auto", Autosubreportname, IIF(Fields!Industry.Value = "Food", Foodsubreportname, (this is the else- so anohter sr or a default reportname???)
or
=Switch(Fields!Industry.Value = "Retail","Retailsubreportname",Fields!Industry.Value = "Auto", "Autosubreportname") etc...
Got it solved. Both RandomShelly and Sanjay gave me ideas to solve it. Basically, I used Sanjay's idea of creating datasets that only contain the data for each ranked industry. He used temp tables but I created permanent dataset definitions in the report. So knowing that the first ranked industry will always be in position 1, I created a dataset called REPORT_POSITION_1 with the following definition:
SELECT *
FROM TOP10_COMPANIES
WHERE NET = :Network
AND INDUSTRY = (SELECT DISTINCT INDUSTRY FROM TOP10_INDUSTRIES WHERE CURR_RANK=1 AND NET=:Network)
ORDER BY CURR_RANK
Note: my source database is Oracle so the ":" syntax for a parameter is correct. I've added the Network parameter since posting. Since the underlying tables only contain a snapshot of the data, I don't need the month parameter.
This dataset is ONLY made up of the data for the first industry so I don't need to use the Industry parameter at all.
Once the various datasets and reports are created, I used RandomShelly's idea of creating dynamic links to call the specific Industry reports through hyperlinks. This will be perfect when I deploy to SharePoint in our dashboard for users to navigate to the information they are looking for.
Thanks to both of you for your help!

Query with multiple WHERE for single column

I need to select all the values where a single column matches multiple values. At one point I saw something like the following but it is not working for me. Is this correct or do I need to link these values with AND?
SELECT * FROM MYTABLE WHERE AGE = ( 20, 21, 22 )
Also im doing this in a php script and getting my values in an http post so if anyone can point me in the direction of a good example that would be great. THanks!
You need to use IN
SELECT *
FROM MYTABLE
WHERE AGE IN ( 20, 21, 22 )
and it is the same as
SELECT *
FROM MYTABLE
WHERE AGE = 20 OR
AGE = 21 OR
AGE = 22
You need to use IN, but be careful:
if the field or the values are not some numeric format, you have to quote each value:
SELECT * FROM TABLE WHERE FIELD IN ('a','b','c')
Also, if you are using numeric fields, be sure that each value is not null. This will fail:
SELECT * FROM TABLE WHERE FIELD IN (1,,3,4,5)
This will throw an error.

sybase cursors in a trigger

I am trying to use a cursor in a trigger on a sybase ASE 15.0.3 system running on Solaris. The purpose for this is that I want to know which column of a table is getting updated. This information I then save in an admin table for further lookups.
create trigger test_trigger on my_table for update as
set nocount on
/* declare cursor */
declare #colname varchar(64)
declare column_name cursor for
select syscolumns.name from syscolumns join sysobjects on (sysobjects.id = syscolumns.id) where sysobjects.name = 'my_table'
/* open the cursor */
open column_name
/* fetch the first row */
fetch column_name into #colname
/* now loop, processing all the rows
** ##sqlstatus = 0 means successful fetch
** ##sqlstatus = 1 means error on previous fetch
** ##sqlstatus = 2 means end of result set reached
*/
while (##sqlstatus != 2)
begin
/* check for errors */
if (##sqlstatus = 1)
begin
print "Error in column_names cursor"
return
end
/* now do the insert if colum was updaed */
if update(#colname)
begin
insert into my_save_table (login,tablename,field,action,pstamp)
select suser_name(),'my_table',#colname,'U',getdate() from inserted
end
/* fetch the next row */
fetch column_name into #colname
end
/* close the cursor and return */
close column_name
go
Unfortunately when trying to run this in isql I get the following error:
Msg 102, Level 15, State 1:
Server 'my_sybase_server', Procedure 'test_trigger', Line 34:
Incorrect syntax near '#colname'.
I did some investigations and found out that line 34 means the following statement:
if update(#colname)
then I tried to just check on 1 column and replaced it by
if update(some_column_name)
That actually worked fine and I don't have any other idea how to fix that. It looks like the update() function somehow not allows to contain a variable. I did not find any additional information on the sybase books or anywhere else in google ect. Does anybody may find a solution for this? Is it may a bug? Are there workarounds for the cursor?
Thanks for any advice
The problem is that update(#colname) is something like update('colname') and needs to be update(colname). In order to you achieve that, you need to use Dynamic SQL.
I've already saw the documentation and it's possible to use:
Dynamically executing Transact-SQL
When used with the string or char_variable options, execute concatenates the supplied strings and variables to execute the
resulting Transact-SQL command. This form of the execute command may
be used in SQL batches, procedures, and triggers.
Check this article for an example on how to use dynamic sql!
If it is not a problem to recreate the trigger every time the table is altered (columns added/dropped) you may just generate the body for your trigger with such query
select
'if update('+c.name+')
set #colname = '''+c.name+'''
'
from syscolumns c where id = object_id('my_table')

How to sort by numbers first with Oracle SQL query?

I have this table with a 'title' field which is varchar2 and I want to select all rows and sort them first by number and then by the alphabet as it normally happens.
For instance, I currently get this using a simple ORDER BY title in the end:
Abc
Def
321
But I want this:
321
Abc
Def
The weird thing is that SQL Developer shows the "right" order, with numbers first. But on my app (PHP using OCI8) it shows numbers last.
Not an Oracle expert, but you are supposed to be able to do it without altering the session with
SELECT * FROM my_data SORT by NLSSORT(title,’NLS_SORT=BINARY_AI’)
where you can change the NLS_SORT= to fit your needs (here are the list of values)
Keep in mind that docs says that this will force table scan, so it might be beneficial to filter them first (but if you are selecting all the table scan is what you are going to use anyway).
The reason why SQL Developer exhibits different behaviour is probably because it changes the session.
the difference in behaviour that you're seeing is probably because of different NLS_SORT parameter setting. Consider:
SQL> select * from nls_session_parameters where parameter='NLS_SORT';
PARAMETER VALUE
------------------------------ ----------------------------------------
NLS_SORT BINARY
SQL> SELECT * FROM my_data order by title;
TITLE
-----
321
Abc
Def
SQL> alter session set nls_sort=french;
Session altered
SQL> SELECT * FROM my_data order by title;
TITLE
-----
Abc
Def
321
You can build a query that should give you the expected result regardless of your NLS_SORT session parameter setting, for example:
SQL> SELECT *
2 FROM my_data
3 ORDER BY CASE
4 WHEN regexp_like(title, '[0-9]+\.?[0-9]*') THEN
5 1
6 ELSE
7 2
8 END, title;
TITLE
-----
321
Abc
Def

Resources