How to export Sybase table contents to a text file? - sybase

I want to export the tables with contents from a Sybase database to a text file. I am using Sybase ASE 15.5 and that can't be changed/upgraded.
I have tried using sp_tables and different Select commands, but they don't give the result I'm looking for.
The output format I'm looking for is something like this:
FIRST_TABLE
Column_1 Column_2 Column_3
Roger Male 51
Anne Female 46
SECOND_TABLE
Column_1 Column_2 Column_3
BMW German Car
Schwinn American Bicycles
etc.etc.

Create a view that generates the output you want and use bcp to copy the data from the view.
Consider the following table, view and data:
create table t1 (
k int not null,
v varchar(255) null)
go
create view v1 as
select
'k' as k,
'v' as v
union all
select
convert(varchar, k),
v
from
t1
go
insert into t1 (k, v) values (1, 'Line_1')
insert into t1 (k, v) values (2, 'Line_2')
insert into t1 (k, v) values (3, 'Line_3')
go
Check the data returned from the view, notice the column names are in the result set. They need to here. Ideally you would query against syscolumns, but there is no pivot statement in ASE, so you need to know the names in advance :-(
select * from v1
go
k v
1 Line_1
2 Line_2
3 Line_3
(4 rows affected)
Now copy the data from the view into the text file:
$ bcp <db_name>..v1 out v1.txt -c -U login_name -S server_name
Password:
Starting copy...
4 rows copied.
Network packet size (bytes): 4096
Clock Time (ms.) Total : 1 Average : (4000.0 rows per sec.)
$ cat v1.txt
k v
1 Line_1
2 Line_2
3 Line_3

Without using BCP
declare cur cursor for
select sc.name from sysobjects so, syscolumns sc
where so.id = sc.id and so.name = 'FIRST_TABLE'
order by sc.colid
go
declare #l_name varchar(30), #l_sql varchar(2000)
begin
open cur
fetch cur into #l_name
while ##sqlstatus = 0
begin
set #l_sql = #l_sql + '''' + #l_name + ''','
fetch cur into #l_name
end
close cur
deallocate cur
set #l_sql = 'select ' + substring(#l_sql,1,len(#l_sql)-1)
set #l_sql = #l_sql + ' union all select * from FIRST_TABLE'
exec (#l_sql)
end
go

Related

Can someone help in converting this SQL Server "update statement" to Oracle

update a
set a.col1 = 1,
a.col2 = 'abc' + CAST(b.colID AS VARCHAR(3))
from #abc a
cross apply
(select top 1 x.col3, x.colID1
from #xyz x
where (x.col3 = a.col3 and
x.colID1 IN (0, 9, 8))) b
Table abc and xyz are temp tables that's why the '#'.
Need to convert the above script to Oracle
below link could help you what you want to achive...
https://oracle-base.com/articles/18c/private-temporary-tables-18c

Return data in pipe del format

I have the below example and trying to run a script in SQL to return data in required format. Just need some help with the "Header", "Data" and "Trailer" part.
H|Peter|Blum|2012/07/30|1
D|11399011005434578|Jason|Smith|8002235091083|0126531988|199 Lever Road Centurion Gauteng 0067|23.45|Your next payment is due on 2012/09/02|2012/07/29|Active
D|11399022005434578|Mike|Smith|8004235091083|0126531988|299 Lever Road Centurion Gauteng 0067|55.00|Your next payment is due on 2012/09/03|2012/06/29|Active
D|11399033005434578|Peter|Smith|8052235091083|0126531988|399 Lever Road Centurion Gauteng 0067|77.99|Your next payment is due on 2012/09/04|2012/05/29|Active
T|3
From the example you have provided I gather that you are trying to create a file.
You need to use a bcp utility to create files.
The way you would approach it is as follows:
CREATE TABLE ##FileData( ID INT IDENTITY, RowString VARCHAR( MAX ))
INSERT INTO ##FileData
SELECT 'H|Peter|Blum|2012/07/30|1'
INSERT INTO ##FileData
SELECT 'D|' + CONVERT( VARCHAR, Col1 ) + '|' + CONVERT( VARCHAR, Col2 ) + '|' + ....
FROM MyTable
/* Get record count */
DECLARE #RowCount = ( SELECT COUNT(*) FROM #FileData ) - 1
INSERT INTO ##FileData
SELECT 'T|' + CONVERT( VARCHAR, #RowCount )
EXEC master..xp_cmdshell
N'bcp "SELECT RowString FROM ##FileData" queryout C:\MyFile.txt -c -r\r\n -S[ServerName] -U[username] -P[password] '
You can add the Header and Trailer with UNION ALL:
SELECT {Query that generates Header}, 0 AS ord
UNION ALL
SELECT {Query that generates Data Rows}, 1 AS ord
UNION ALL
SELECT {Query that generates Trailer}, 2 AS ord
ORDER BY ord ASC

Increment Numbers with Alphabets In SQL Server Table

My Table structure is
id type no amount
1 type1 a1 1000
2 type1 a2 2000
3 type2 b1 3000
4 type3 c1 4000
5 type1 a3 5000
6 type2 b2 6000
7 type2 b3 7000
8 type3 c2 8000
now i wants to increment the no field data based on the type.
for example for type1 the next no is a4
and
for numeric only I am using the following code
SELECT ISNULL(Max(No),0)+1 AS No FROM table
but how to do it for with Alphabets in SQL Server 2005
Assuming that prefixes are of single character length, you may try following:
;with cte as (
select type, typePrefix = left(no, 1), typeNum = right(no, len(no) - 1)
from TableName
)
select typePrefix + cast(isnull(max(typeNum), 0) + 1 as varchar(10))
from cte
where type = 'type1'
group by typePrefix
But it will not work if you try to generate next no for a type which is not in table (e.g. 'type4'). To allow it, you may need a separate table, where prefix for each type is specified:
create table TypePrefixes (type varchar(50), prefix varchar(10))
insert into TypePrefixes values ('type1', 'a')
insert into TypePrefixes values ('type2', 'b')
insert into TypePrefixes values ('type3', 'c')
insert into TypePrefixes values ('another_type', 'd')
--etc.
In this case, statement to get next no will look as:
select tp.prefix + cast(isnull(max(cast(right(t.no, len(t.no) - len(tp.prefix)) as int)), 0) + 1 as varchar(20))
from TableName t
right join TypePrefixes tp on tp.type = t.type
where tp.type = 'type4'
group by tp.prefix
Also, you may just wish to calculate no for each record on the fly, like:
;with cte as (
select *,
typeNum = row_number() over (partition by type order by id),
typePrefix = char(dense_rank() over (order by type) + ascii('a') - 1)
from TableName
)
select *, No2 = typePrefix + cast(typeNum as varchar(10))
from cte
However, the latter is limited in number of distinct types in your table, which should not exceed 26 (so that we not go beyond 'z').
try something like
SELECT ISNULL(Max(No),0)+1 AS No FROM table group by type
First, you need an UNIQUE index on No column:
CREATE UNIQUE INDEX IUN_MyTable_On
ON MySchema.MyTable(On);
GO
This unique index will prevent duplicate values but, also, will help the query below.
Second, you could use this script to generate the next No for a given letter:
DECLARE #Chr CHAR(1);
SET #Chr='A';
BEGIN TRY
BEGIN TRANSACTION;
DECLARE #LastId INT;
DECLARE #NewNo VARCHAR(...); -- Fill with No's max. length
-- Previous index will help this query
SELECT #LastId=MAX( CONVERT(INT,SUBSTRING(#LastNo,2,8000)) )
FROM MySchema.MyTable x WITH(UPDLOCK) -- It locks the rows to prevent a concurent session to generate the same value (No)
WHERE x.No LIKE #Chr+'%';
SET #NewNo=#Chr+CONVERT(VARCHAR(11),ISNULL(#LastId,0)+1);
-- Do whatever you want with the new value: ex. INSERT
INSERT INTO ... (No,...)
VALUES (#NewNo,...);
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
DECLARE #ErrMsg NVARCHAR(2000);
SET #ErrMsg=ERROR_MESSAGE();
IF ##TRANCOUNT>0
BEGIN
ROLLBACK;
END
RAISERROR(#ErrMsg,16,1);
END CATCH
Note #1: This solution should be safe if this is the only way to generate the new values (#NewNo).
Note #2: If that SELECT query acquires at least 5000 locks then SQL Server will escalate locks at table/partition level.

Convert Bit field table to table

I have a table showing locations with a BIT column for each tool in use at each location:
CREATE TABLE dbo.[ToolsSelected] (
[LocationID] NVARCHAR(40) NOT NULL,
[Tool1] INTEGER DEFAULT 0 NOT NULL,
[Tool2] INTEGER DEFAULT 0 NOT NULL,
[Tool3] INTEGER DEFAULT 0 NOT NULL,
[Tool4] INTEGER DEFAULT 0 NOT NULL,
PRIMARY KEY ([LocationID])
);
LocID Tool1 Tool2 Tool3 Tool4
----- ----- ----- ----- -----
AZ 0 1 1 0
NY 1 0 1 1
I need to convert this to a table by LocationID indicating which tools at which locations:
CREATE TABLE dbo.[ByLocation] (
[LocationID] NVARCHAR(40) NOT NULL,
[Tool] NVARCHAR(40) NOT NULL, -- Column title of ToolsSelected table
PRIMARY KEY ([LocationID], [Tool])
);
LocID Tool
----- -----
AZ Tool2
AZ Tool3
NY Tool1
NY Tool3
NY Tool4
The idea is that each location can select the tools they need, I then need to query the tools table to get details (versions, etc) for each tool selected. Each location is unique; each tool is unique. Is there a way to do this or a much better implementation?
Here is the answer to the immediate question, given only 4 tools columns:
SELECT LocID = LocationID, Tool
FROM
(
SELECT LocationID, Tool = 'Tool1' FROM dbo.ToolsSelected WHERE Tool1 = 1
UNION ALL
SELECT LocationID, Tool = 'Tool2' FROM dbo.ToolsSelected WHERE Tool2 = 1
UNION ALL
SELECT LocationID, Tool = 'Tool3' FROM dbo.ToolsSelected WHERE Tool3 = 1
UNION ALL
SELECT LocationID, Tool = 'Tool4' FROM dbo.ToolsSelected WHERE Tool4 = 1
) AS x
ORDER BY LocID, Tool;
With 40 columns, you could do the same thing, but along with the desire to generate this dynamically:
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'';
SELECT #sql += '
UNION ALL
SELECT LocationID, Tool = ''' + name + '''
FROM dbo.ToolsSelected WHERE ' + name + ' = 1'
FROM sys.columns WHERE [object_id] = OBJECT_ID('dbo.ToolsSelected')
AND name LIKE 'Tool[0-9]%';
SELECT #sql = N'SELECT LocID = LocationID, Tool
FROM
(' + STUFF(#sql, 1, 17, '') + '
) AS x ORDER BY LocID, Tool;';
PRINT #sql;
-- EXEC sp_executesql #sql;
*BUT*
Storing these as separate columns is a recipe for disaster. So when you add Tool41, Tool42 etc. you have to change the schema then change all your code that passes the column names and 1/0 via parameters etc. Why not represent these as simple numbers, e.g.
CREATE TABLE dbo.LocationTools
(
LocID NVARCHAR(40),
ToolID INT
);
So in the above case you would store:
LocID Tool
----- ----
AZ 2
AZ 3
NY 1
NY 3
NY 4
Now when you pass in the checkboxes they've selected, presumably from the front end you are receiving two values, such as:
LocID: "NY"
Tools: "Tool1, Tool5, Tool26"
If that's about right, then you can populate the table when a user creates or changes their choice, first using a split function to break up the comma-separated list dictated by the checkboxes:
CREATE FUNCTION dbo.SplitTools
(
#ToolList NVARCHAR(MAX)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
(
SELECT ToolID = y.i.value('(./text())[1]', 'int')
FROM
(
SELECT x = CONVERT(XML,
'<i>' + REPLACE(REPLACE(#List, ',', '</i><i>'), 'Tool', '')
+ '</i>').query('.')
) AS a CROSS APPLY x.nodes('i') AS y(i)
);
GO
(You forgot to tell us which version of SQL Server you are using - if 2008 or above you could use a table-valued parameter as an alternative to a split function.)
Then a procedure to handle it:
CREATE PROCEDURE dbo.UpdateLocationTools
#LocID NVARCHAR(40),
#Tools NVARCHAR(MAX)
AS
BEGIN
SET NOCOUNT ON;
-- in case they had previously selected tools
-- that are no longer selected, clear first:
DELETE dbo.LocationTools WHERE LocID = #LocID;
INSERT dbo.LocationTools(LocID, ToolID)
SELECT #LocID, ToolID
FROM dbo.SplitTools(#Tools);
END
GO
Now you can add new tool #s without changing schema or code, since your list of checkboxes could also be generated from your data - assuming you have a dbo.Tools table or want to add one. This table could also be used for data integrity purposes (you could put a foreign key on dbo.LocationTools.ToolID).
And you can generate your desired query very simply:
SELECT LocID, Tool = 'Tool' + CONVERT(VARCHAR(12), ToolID)
FROM dbo.LocationTools
ORDER BY LocID, ToolID;
No redundant data, no wide tables with unmanageable columns, and a proper index can even help you search for, say, all locations using Tool3 efficiently...

TSQL - A join using full-text CONTAINS

I currently have the following select statement, but I wish to move to full text search on the Keywords column. How would I re-write this to use CONTAINS?
SELECT MediaID, 50 AS Weighting
FROM Media m JOIN #words w ON m.Keywords LIKE '%' + w.Word + '%'
#words is a table variable filled with words I wish to look for:
DECLARE #words TABLE(Word NVARCHAR(512) NOT NULL);
If you are not against using a temp table, and EXEC (and I realize that is a big if), you could do the following:
DECLARE #KeywordList VARCHAR(MAX), #KeywordQuery VARCHAR(MAX)
SELECT #KeywordList = STUFF ((
SELECT '"' + Keyword + '" OR '
FROM FTS_Keywords
FOR XML PATH('')
), 1, 0, '')
SELECT #KeywordList = SUBSTRING(#KeywordList, 0, LEN(#KeywordList) - 2)
SELECT #KeywordQuery = 'SELECT RecordID, Document FROM FTS_Demo_2 WHERE CONTAINS(Document, ''' + #KeywordList +''')'
--SELECT #KeywordList, #KeywordQuery
CREATE TABLE #Results (RecordID INT, Document NVARCHAR(MAX))
INSERT INTO #Results (RecordID, Document)
EXEC(#KeywordQuery)
SELECT * FROM #Results
DROP TABLE #Results
This would generate a query like:
SELECT RecordID
,Document
FROM FTS_Demo_2
WHERE CONTAINS(Document, '"red" OR "green" OR "blue"')
And results like this:
RecordID Document
1 one two blue
2 three red five
If CONTAINS allows a variable or column, you could have used something like this.
SELECT MediaID, 50 AS Weighting
FROM Media m
JOIN #words w ON CONTAINS(m.Keywords, w.word)
However, according to Books Online for SQL Server CONTAINS, it is not supported. Therefore, no there is no way to do it.
Ref: (column_name appears only in the first param to CONTAINS)
CONTAINS
( { column_name | ( column_list ) | * }
,'<contains_search_condition>'
[ , LANGUAGE language_term ]
)

Resources