I dived into documentation but since I didn't find any information (Well, actually I found similarities with some other SO questions but not what I want), I'm asking you guys to help me :
I'm executing a tsql query over an ADODB connection, to retrieve data from an Excel File (*.xlsx) into another one.
This file is composed as follow :
Header1 Header2 Header3
--------- --------- ---------
A1 B1 C1
A2 B2 C2
A3 B3 C3
.... .... ....
I want to retrieve the headers too so here's a part of the whole program, containing the connection string
Dim con As ADODB.Connection
Dim rs As ADODB.Recordset
Set con = New ADODB.Connection
Set rs = New ADODB.Recordset
With con
.Provider = "Microsoft.ACE.OLEDB.12.0"
.ConnectionString = "Data Source=path\file.xlsx; _
Extended Properties=""Excel 12.0 Xml;HDR=NO;IMEX=1"""
Set rs = .Execute("Select * From [Sheet1$]")
.Close
End With
Here I retrieve all the columns, but what if I want column B, then column A, then column C, e.g. something like that :
Set rs = .Execute("Select colb, cola, colc From [Sheet1$]")
The problem there is that I don't know the terms which should replace colb, cola, colc since I can't use the headers of the columns
Regards
PS : I don't know much about these technologies, so I may be wrong with the terminology.
Not my answer, but from a colleague who sits next to me ;)
Set rs = .Execute("SELECT F2, F1, F3 FROM [Sheet1$]")
(not tested)
Have you tried to read the columns as they are in the file:
Set rs = .Execute("SELECT * FROM [Sheet1$]")
and later map them to the required variables? I mean - what do you do with rs later in your code?
Related
I have two queries
first one return latest Revision number for each date for a month
select max(a.wdcm_revision_no)
from wb_declared_capacity_master a, wb_declared_capacity_det_unit b
where a.wdcm_internal_id = b.wdcd_ref_id and b.wdcm_unit = 'HSY_Unit1' and to_char(a.wdcm_date,'MM YYYY')='08 2019' group by a.wdcm_date
And second query which returns all the data irrespective of any revision
select a1.wdcm_date, b1.wdcd_block_no, c1.wdcd_capacity, c1.wdcd_approval, a1.wdcm_revision_no
from wb_declared_capacity_master a1, wb_declared_capacity_det_unit b1, wb_declared_capacity_detail c1
where a1.wdcm_internal_id = b1.wdcd_ref_id and a1.wdcm_internal_id = c1.wdcd_ref_id and b1.wdcm_unit = 'HSY_Unit1' and to_char(a1.wdcm_date,'MM YYYY')='08 2019'and b1.wdcd_block_no = c1.wdcd_block_no
Now I want to pass each date's latest revision from first query in where condition of second query expecting to return all the values based on those latest revision number
You can combine then into 1 query. The 1st becoming a CTE which is then fed into the 2nd. I believe the following is close, but as you didn't actually indicate where you wanted to "pass in the result" I'm making assumption that seems likely, but it's still an assumption.
with latest (revision) as
-- first query
( select max(a.wdcm_revision_no)
from wb_declared_capacity_master a
, wb_declared_capacity_det_unit b
where a.wdcm_internal_id = b.wdcd_ref_id
and b.wdcm_unit = 'HSY_Unit1'
and to_char(a.wdcm_date,'MM YYYY')='08 2019'
group by a.wdcm_date
)
-- And second query which returns all the data irrespective of any revision
select a1.wdcm_date
, b1.wdcd_block_no
, c1.wdcd_capacity
, c1.wdcd_approval
, a1.wdcm_revision_no
from wb_declared_capacity_master a1
, wb_declared_capacity_det_unit b1
, wb_declared_capacity_detail c1
, latest
where a1.wdcm_internal_id = b1.wdcd_ref_id
and a1.wdcm_internal_id = c1.wdcd_ref_id
and b1.wdcm_unit = 'HSY_Unit1'
and to_char(a1.wdcm_date,'MM YYYY')='08 2019'
and b1.wdcd_block_no = c1.wdcd_block_no
and a1.wdcm_revision_no = latest.revision; ---- you didn't actually say where to "pass it in" this seems likely
I've kept the join format you used but you really should begin using the modern ANSI/ISO standard join format. (Modern meaning being in ONLY since 1992 or so).
How can we identify the triggers associated with a table in a Informix database?
select tabname,a.* from systriggers a, systables b
where a.tabid=b.tabid and tabname="TableName"
or
dbschema -d db -t tablename
The information is in the SysTriggers and SysTrigBody system catalog tables — primarily SysTriggers. You can find the description of these (and all other system catalog tables) in the Informix Guide to SQL: Reference manual. You can find that at the Informix 11.70 Info Centre. In particular, the tabid (from SysTables) identifies the triggers for a table in SysTriggers.
As Jonathan answered you can use systriggers and other system catalog tables. I used them in my schema reporting utility: http://code.activestate.com/recipes/576621-dump-informix-schema-to-text/
This utility can work with Python and ODBC or with Jython and JDBC. It shows info about trigger for every table like:
--- triggers ---
defbookacc defbookacc_dtrg D
defbookacc defbookacc_itrg I
defbookacc defbookacc_utrg U
mc_loadman loadman_del D
and then shows body for each trigger.
--OBTIENE LOS TRIGGERS DE LA TABLA:
SELECT T.tabid, TRIM(T.owner) owner, T.tabname, TR.trigid, TRIM(TR.owner) tr_owner, TR.trigname, TR.event, TR.old, TR.new, TR.mode, TRIM(TR.collation) collation,
TB.datakey, TB.seqno, TB.data
FROM systables T, systriggers TR, systrigbody TB
WHERE T.tabname = 'table_name' AND TR.tabid = T.tabid AND TB.trigid = TR.trigid AND TB.datakey IN ('D', 'A')
ORDER BY TB.trigid, TB.datakey DESC, TB.seqno ASC;
--Event: type of triggering event: D = Delete trigger, I = Insert trigger ,U = Update trigger ,S = Select trigger , d = INSTEAD OF Delete trigger , i = INSTEAD OF Insert trigger ,u = INSTEAD OF Update trigger (IDS)
--Old: Name of value before update.
--New: Name of value after update.
--DataKey: Code specifying the type of data: A = ASCII text for the body, triggered actions, B = Linearized code for the body, D = English text for the header, trigger definition, H = Linearized code for the header, S = Linearized code for the symbol table.
Background
Currently I am using DB2 V9 version. One of my stored procedure is taking time to execute. I looked BMC apptune and found the following SQL.
There are three tables we were using to execute the following query.
ACCOUNT table is having 3413 records
EXCHANGE_RATE is having 1267K records
BALANCE is having 113M records
Someone has added recently following piece of code in the query. I think because of this we had a problem.
AND (((A.ACT <> A.EW_ACT)
AND (A.EW_ACT <> ' ')
AND (C.ACT = A.EW_ACT))
OR (C.ACT = A.ACT))
Query
SELECT F1.CLO_LED
INTO :H :H
FROM (SELECT A.ACT, A.BNK, A.ACT_TYPE,
CASE WHEN :H = A.CUY_TYPE THEN DEC(C.CLO_LED, 21, 2)
ELSE DEC(MULTIPLY_ALT(C.CLO_LED, COALESCE(B.EXC_RATE, 0)), 21, 2)
END AS CLO_LED
FROM ACCOUNT A
LEFT OUTER JOIN EXCHANGE_RATE B
ON B.EFF_DATE = CURRENT DATE - 1 DAY
AND B.CURCY_FROM = A.CURNCY_TYPE
AND B.CURCY_TO = :H
AND B.STA_TYPE = 'A'
, BALANCE C
WHERE A.CUSR_ID = :DCL.CUST-ID
AND A.ACT = :DCL.ACT
AND A.EIG_RTN = :WS-BNK-ID
AND A.ACT_TYPE = :DCL.ACT-TYPE
AND A.ACT_CAT = :DCL.ACT-CAT
AND A.STA_TYPE = 'A'
AND (((A.ACT <> A.EW_ACT)
AND (A.EW_ACT <> ' ')
AND (C.ACT = A.EW_ACT))
OR (C.ACT = A.ACT))
AND C.BNK = :WS-BNK-ID
AND C.ACT_TYPE = :DCL.ACT-TYPE
AND C.BUS_DATE = :WS-DATE-FROM) F1
WITH UR
There's a number of wierd things going on in this query. The most twitchy of which is mixing explicit joins with the implicit-join syntax; frankly, I'm not certain how the system interprets it. You also appear to be using the same host-variable for both input and output; please don't.
Also, why are your column names so short? DB2 (that version, at least) supports column names that are much longer. Please save people's sanity, if at all possible.
We can't completely say why things are slow - we may need to see access plans. In the meantime, here's your query, restructured to what may be a faster form:
SELECT CASE WHEN :inputType = a.cuy_type THEN DEC(b.clo_led, 21, 2)
ELSE DEC(MULTIPLY_ALT(b.clo_led, COALESCE(c.exc_rate, 0)), 21, 2) END
INTO :amount :amountIndicator -- if you get results, do you need the indiciator?
FROM Account as a
JOIN Balance as b -- This is assumed to not be a 'left', given coalesce not used
ON b.bnk = a.eig_rtn
AND b.act_type = a.act_type
AND b.bus_date = :ws-date-from
AND ((a.act <> a.ew_act -- something feels wrong here, but
AND a.ew_act <> ' ' -- without knowing the data, I don't
AND c.act = a.ew_act) -- want to muck with it.
OR c.act = a.act)
LEFT JOIN Exchange_Rate as c
ON c.eff_date = current_date - 1 day
AND c.curcy_from = a.curncy_type
AND c.sta_type = a.sta_type
AND c.curcy_to = :destinationCurrency
WHERE a.cusr_id = :dcl.cust-id
AND a.act = :dcl.act
AND a.eig_rtn = :ws-bnk-id
AND a.act_type = :dcl.act-type
AND a.act_cat = :dcl.act-cat
AND a.sta_type = 'A'
WITH UR
FECTCH FIRST 1 ROW ONLY
A few other notes:
Only specify exactly those columns needed - under certain circumstances, this permits index-only access, where otherwise a followup table-access may be needed. However, this probably won't help here.
COALESCE(c.exc_rate, 0) feels off somehow - if no exchange rate is present, you return an amount of 0, which could otherwise be a valid amount. You may need to return some sort of indicator, or make it a normal join, not an outer one.
Also, try both this version, and possibly a version where host variables are specified in addition to the conditions between tables. The optimizer should be able to automatically commute the values, but may not under some conditions (implementation detail).
I'm trying to figure out a way to store metadata about a column without repeating myself.
I'm currently working on a generic dimension loading SSIS package that will handle all my dimensions. It currently does :
Create a temporary table identical to the given table name in parameters (this is a generic stored procedure that receive the table name as parameter, and then do : select top 0 * into ##[INSERT ORIGINAL TABLE NAME HERE] from [INSERT ORIGINAL TABLE NAME HERE]).
==> Here we insert custom code for this particular dimension that will first query the data from a datasource and get my delta, then transform the data and finally loads it into my temporary table.
Merge the temporary table into my original table with a T-SQL MERGE, taking care of type1 and type2 fields accordingly.
My problem right now is that I have to maintain a table with all the fields in it to store a metadata to tell my scripts if this particular field is type1 or type2... this is nonsense, I can get the same data (minus type1/type2) from sys.columns/sys.types.
I was ultimately thinking about renaming my fields to include their type in it, such as :
FirstName_T2, LastName_T2, Sex_T1 (well, I know this can be type2, let's not fall into that debate here).
What do you guyz would do with that? My solution (using a table with that metadata) is currently in place and working, but it's obvious that repeating myself from the systables to a custom table is nonsense, just for a simple type1/type2 info.
UPDATE: I also thought about creating user defined types like varchar => t1_varchar, t2_varchar, etc. This sounds like something a bit sluggy too...
Everything you need should already be in INFORMATION_SCHEMA.COLUMNS
I can't follow your thinking of not using provided tables/views...
Edit: As scarpacci mentioned, this somewhat portable if needed.
I know this is bad, but I will post an answer to my own question... Thanks to GBN for the help tho!
I am now storing "flags" in the "description" field of my columns. I, for example, can store a flag this way : "TYPE_2_DATA".
Then, I use this query to get the flag back for each and every column :
select columns.name as [column_name]
,types.name as [type_name]
,extended_properties.value as [column_flags]
from sys.columns
inner join sys.types
on columns.system_type_id = types.system_type_id
left join sys.extended_properties
on extended_properties.major_id = columns.object_id
and extended_properties.minor_id = columns.column_id
and extended_properties.name = 'MS_Description'
where object_id = ( select id from sys.sysobjects where name = 'DimDivision' )
and is_identity = 0
order by column_id
Now I can store metadata about columns without having to create a separate table. I use what's already in place and I don't repeat myself. I'm not sure this is the best possible solution yet, but it works and is far better than duplicating information.
In the future, I will be able to use this field to store more metadata, where as : "TYPE_2_DATA|ANOTHER_FLAG|ETC|OH BOY!".
UPDATE :
I now store the information in separate extended properties. You can manage extended properties using sp_addextendedproperty and sp_updateextendedproperty stored procedures. I have created a simple store procedure that help me to update those values regardless if they currently exist or not :
create procedure [dbo].[UpdateSCDType]
#tablename nvarchar(50),
#fieldname nvarchar(50),
#scdtype char(1),
#dbschema nvarchar(25) = 'dbo'
as
begin
declare #already_exists int;
if ( #scdtype = '1' or #scdtype = '2' )
begin
select #already_exists = count(1)
from sys.columns
inner join sys.extended_properties
on extended_properties.major_id = columns.object_id
and extended_properties.minor_id = columns.column_id
and extended_properties.name = 'ScdType'
where object_id = (select sysobjects.id from sys.sysobjects where sysobjects.name = #tablename)
and columns.name = #fieldname
if ( #already_exists = 0 )
begin
exec sys.sp_addextendedproperty
#name = N'Scd_Type',
#value = #scdtype,
#level0type = N'SCHEMA',
#level0name = #dbschema,
#level1type = N'TABLE',
#level1name = #tablename,
#level2type = N'COLUMN',
#level2name = #fieldname
end
else
begin
exec sys.sp_updateextendedproperty
#name = N'Scd_Type',
#value = #scdtype,
#level0type = N'SCHEMA',
#level0name = #dbschema,
#level1type = N'TABLE',
#level1name = #tablename,
#level2type = N'COLUMN',
#level2name = #fieldname
end
end
end
Thanks again
I'm using ODP to update an Oracle 10g DB with no success updating decimal values.
Ex:
UPDATE usertable.fiche SET DT_MAJ = '20110627',var = 60.4 WHERE NB = '2143'
Result: 604 in the var column ('.' disappears)
UPDATE usertable.fiche SET DT_MAJ = '20110627',var = 60,4 WHERE NB = '2143'
Result: INVALID NUMBER
UPDATE usertable.fiche SET DT_MAJ = '20110627',var = ‘60,4’ WHERE NB = '2143'
Result: INVALID NUMBER
I also tried to use TO_NUMBER function without any success.
Any idea on the correct format I should use?
Thanks.
You didn't give us much to go on (only the insert statements, not the casting of types or what not)
but here is a test case that shows the how to do it.
create table numTest(numA number(3) ,
numB number(10,8) ,
numC number(10,2) )
/
--test insert
insert into numTest(numA, numB, numC) values (123, 12.1241, 12.12)
/
select * from numTest
/
/*
NUMA NUMB NUMC
---------------------- ---------------------- ----------------------
123 12.1241 12.12
*/
--delete to start clean
rollback
/
/*by marking these table.col%type we can change the table type and not have to worry about changing these in the future!*/
create or replace procedure odpTestNumberInsert(
numA_in IN numTest.numA%type ,
numB_in IN numTest.numB%type ,
numC_in IN numTest.numC%type)
AS
BEGIN
insert into numTest(numA, numB, numC) values (numA_in, numB_in, numC_in) ;
END odpTestNumberInsert ;
/
begin
odpTestNumberInsert(numA_in => 10
,numB_in => 12.55678
,numC_in => 13.13);
odpTestNumberInsert(numA_in => 20
,numB_in => 30.667788
,numC_in => 40.55);
end ;
/
select *
from numTest
/
/*
NUMA NUMB NUMC
---------------------- ---------------------- ----------------------
10 12.55678 13.13
20 30.667788 40.55
*/
rollback
/
okay, so we have created a table, got data in it (removed it), created a procedure to verify it works (then rollback the changes) and all looks good. So let's go to the .net side (I'll assume C#)
OracleCommand cmd = new OracleCommand("odpTestNumberInsert", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.BindByName = true;
OracleParameter oparam0 = cmd.Parameters.Add("numA_in", OracleDbType.Int64);
oparam0.Value = 5 ;
oparam0.Direction = ParameterDirection.Input;
decimal deciVal = (decimal)55.556677;
OracleParameter oparam1 = cmd.Parameters.Add("numB_in", OracleDbType.Decimal);
oparam1.Value = deciVal ;
oparam1.Direction = ParameterDirection.Input;
OracleParameter oparam2 = cmd.Parameters.Add("numC_in", OracleDbType.Decimal);
oparam2.Value = 55.66 ;
oparam2.Direction = ParameterDirection.Input;
cmd.ExecuteNonQuery ();
con.Close();
con.Dispose();
And then to finish things off:
select *
from numTest
/
NUMA NUMB NUMC
---------------------- ---------------------- ----------------------
5 55.556677 55.66
all of our data was inserted.
Without more code on your part I would recommend that you verify that the correct param is being passed in and assoc. to the insert. the above proves it works.
You Should Not re-cast your variables via a TO_NUMBER when you can do so when creating the parameters.
I found the problem just after posting my question !!! I was not looking at the right place... Oracle update was not concerned at all. The problem was in the Decimal.parse method I was using to convert my input string (containing a coma as decimal separator) into the decimal number (with a dot as decimal separatot) I wanted to update in the DB. The thing is that the system culture is not the same on my own development computer than on the client computer, even if they both run in the same country. Then the parse was perfectly working on my computer but was removing the decimal character on the client production environment. I finally just put in place a "replace" coma by dot and everything goes well now. Thanks again for your time.