In mysql i m having a stored procedure which has a sql like:
select firstname as i_firstname , lastname as i_lastname from roleuser
where user_id = uid ;
I m using a jstl code to get the values: -
<sql:query var="comm_codes" dataSource="jdbc/myDatasource">
call sp_select_username(?);
<sql:param>${user_id}</sql:param>
</sql:query>
<c:forEach var="rows" items="${comm_codes.rows}">
${rows.i_firstname} ${rows.i_lastname}
</c:forEach>
But this code does not return anything but when the replace the above code ${rows.i_firstname} with ${rows.firstname} i get the correct values.
Anything wrong with jstl, is this replicable or my fault here...
Question also posted here and here
thanks
I know it is an old post, but I encountered this problem as well. It is discussed here: http://forums.mysql.com/read.php?39,432843,432862#msg-432862
Importantly, the poster in the mysql forum states
ResultSetMetaData.getColumnName() will return the actual name of the column, if it exists
This provides a work-around - prevent the column name from existing, so that the alias must be used. As an example, the original poster's stored procedure could be modified to be
select concat(first name,'') as i_firstname ,
concat(lastname,'') as i_lastname from roleuser
where user_id = uid ;
In this case, the original column is now unknown, and the alias is used. I've tested this on my system in a similar situation at it worked. Likewise, if you need to use an alias for an int, you can try SELECT (id+0) AS id_alias. I'm sure most column types have similar solutions. Hope this helps.
Related
I have a db upgrade script to change some datatypes on a few columns. I want to do a preCondition check, and call ALTER TABLE only when it is a DECIMAL datatype, but I will want it to be changed to INTEGER.
Couldn't find a predefined precondition for this, and could not write an sqlCheck either.
There's no built-in precondition for column's dataType in liquibase.
You may just check whether the column exists or not. If it's already of the datatype you need, no error will be thrown.
OR
You can use sqlCheck in your preconditions and it'll be something like this:
<preConditions onFail="MARK_RAN">
<not>
<sqlCheck expectedResult="DECIMAL">
SELECT DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'your_table_name'
AND COLUMN_NAME = 'your_column_name'
</sqlCheck>
</not>
</preConditions>
Another answer already mentions how to do a sqlcheck. However, the actual SQL for Teradata would be something different.
In Teradata you would use a query similar to the following and expect the columnType='D' for decimal values
Select ColumnType
From DBC.ColumnsV
Where databasename='yourdatabasename'
and tablename='yourtablename'
and columnname='yourcolumnname';
You could also do something like this if you want a more human readable column type instead of a type code:
Select Type(tablename.columnname);
I know the question was for Teradata, but principle is the same.
I prefer SQL files, so in changelog I have (for Oracle), is:
<include file="roles.sql" relativeToChangelogFile="true" />
and then in roles.sql
there is
--changeset betlista:2022-01-04_2200-87-insert
--preconditions onFail:MARK_RAN
--precondition-sql-check expectedResult:0 select count(*) from ddh_audit.DDH_USER_ROLE where id = 87;
insert into ddh_audit.DDH_USER_ROLE(id, role_name, description)
values(87, 'CONTAINERS_READONLY', 'Can read Containers reference data');
the query added by David Cram would make the trick.
I do not know and I didn't try if condition could be on multiple lines, I know --rollback can.
I have a Spring Batch project running in Spring Boot that is working perfectly fine. For my reader I'm using JdbcPagingItemReader with a MySqlPagingQueryProvider.
#Bean
public ItemReader<Person> reader(DataSource dataSource) {
MySqlPagingQueryProvider provider = new MySqlPagingQueryProvider()
provider.setSelectClause(ScoringConstants.SCORING_SELECT_STATEMENT)
provider.setFromClause(ScoringConstants.SCORING_FROM_CLAUSE)
provider.setSortKeys("p.id": Order.ASCENDING)
JdbcPagingItemReader<Person> reader = new JdbcPagingItemReader<Person>()
reader.setRowMapper(new PersonRowMapper())
reader.setDataSource(dataSource)
reader.setQueryProvider(provider)
//Setting these caused the exception
reader.setParameterValues(
startDate: new Date() - 31,
endDate: new Date()
)
reader.afterPropertiesSet()
return reader
}
However, when I modified my query with some named parameters to replace previously hard coded date values and set these parameter values on the reader as shown above, I get the following exception on the second page read (the first page works fine because the _id parameter hasn't been made use of by the paging query provider):
org.springframework.dao.InvalidDataAccessApiUsageException: No value supplied for the SQL parameter '_id': No value registered for key '_id'
at org.springframework.jdbc.core.namedparam.NamedParameterUtils.buildValueArray(NamedParameterUtils.java:336)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.getPreparedStatementCreator(NamedParameterJdbcTemplate.java:374)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.query(NamedParameterJdbcTemplate.java:192)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.query(NamedParameterJdbcTemplate.java:199)
at org.springframework.batch.item.database.JdbcPagingItemReader.doReadPage(JdbcPagingItemReader.java:218)
at org.springframework.batch.item.database.AbstractPagingItemReader.doRead(AbstractPagingItemReader.java:108)
Here is an example of the SQL, which has no WHERE clause by default. One does get created automatically when the second page is read:
select *, (select id from family f where date_created between :startDate and :endDate and f.creator_id = p.id) from person p
On the second page, the sql is modified to the following, however it seems that the named parameter for _id didn't get supplied:
select *, (select id from family f where date_created between :startDate and :endDate and f.creator_id = p.id) from person p WHERE id > :_id
I'm wondering if I simply can't use the MySqlPagingQueryProvider sort keys together with additional named parameters set in JdbcPagingItemReader. If not, what is the best alternative to solving this problem? I need to be able to supply parameters to the query and also page it (vs. using the cursor). Thank you!
I solved this problem with some intense debugging. It turns out that MySqlPagingQueryProvider utilizes a method getSortKeysWithoutAliases() when it builds up the SQL query to run for the first page and for subsequent pages. It therefore appends and (p.id > :_id) instead of and (p.id > :_p.id). Later on, when the second page sort values are created and stored in JdbcPagingItemReader's startAfterValues field it will use the original "p.id" String specified and eventually put into the named parameter map the pair ("_p.id",10). However, when the reader tries to fill in _id in the query, it doesn't exist because the reader used the non-alias removed key.
Long story short, I had to remove the alias reference when defining my sort keys.
provider.setSortKeys("p.id": Order.ASCENDING)
had to change to in order for everything to work nicely together
provider.setSortKeys("id": Order.ASCENDING)
I had the same issue and got another possible solution.
My table T has a primary key field INTERNAL_ID.
The query in JdbcPagingItemReader was like this:
SELECT INTERNAL_ID, ... FROM T WHERE ... ORDER BY INTERNAL_ID ASC
So, the key is: in some conditions, the query didn't return results, and then, raised the error above No value supplied for...
The solution is:
Check in a Spring Batch decider element if there are rows.
If it is, continue with chunk: reader-processor-writer.
It it's not, go to another step.
Please, note that they are two different scenarios:
At the beginning, there are rows. You get them by paging and finally, there are no more rows. This has no problem and decider trick is not required.
At the beginning, there are no rows. Then, this error raised, and the decider solved it.
Hope this helps.
Hi I'm trying to use collate on a view which has column name per_va_first_name when I use the following query :
SELECT *
FROM person_view
WHERE NLSSORT(per_va_first_name, 'NLS_SORT = FRENCH_AI') = NLSSORT('mickaël', 'NLS_SORT =FRENCH_AI')
I get the error
ORA-12702: invalid NLS parameter string used in SQL function
I'm new to oracle and this nlssort. Can anyone help me in pointing out what's my mistake?
And at the same time I want to use collate in Hibernate for Java. Same french char set.
Edit:
When I use these commands in sql
alter session set nls_sort=French_AI;
alter session set nls_comp=linguistic;
I get the desired output when this query is executed
SELECT * FROM v_myuser_search_test_ea4 where per_va_first_name like 'Mickaël%'
How to do this in Hibernate? Is there a way I can append 'CI' to French_AI to make it 'French_AI_CI'
According to Oracle documentation found on http://docs.oracle.com/cd/E11882_01/server.112/e26088/functions113.htm#SQLRF51562
you might change your query to
SELECT *
FROM person_view
ORDER BY NLSORT(per_va_first_name, 'NLS_SORT = FRENCH_AI_CI')
Hibernate should understand it, however you are already losing database portability as this is Oracle-specific function.
I am attempting to use zxJDBC to connect to a database running on SQL Server 2008 R2 (Express) and call a stored procedure, passing it a single parameter. I am using jython-standalone 2.5.3 and ideally do not want to have to install additional modules.
My test code is shown below.
The database name is CSM
Stored Procedure:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
CREATE PROCEDURE dbo.DUMMY
-- Add the parameters for the stored procedure here
#carrierId VARCHAR(50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
INSERT INTO dbo.carrier (carrierId, test)
VALUES (#carrierId, 'Success')
END
GO
Jython Script:
from com.ziclix.python.sql import zxJDBC
conn = None
try :
conn = zxJDBC.connect('jdbc:sqlserver://localhost\SQLEXPRESS', 'sa', 'password', 'com.microsoft.sqlserver.jdbc.SQLServerDriver')
cur = conn.cursor()
cur.callproc(('CSM','dbo','DUMMY'), ['carrier1'])
conn.commit()
except Exception, err :
print err
if conn:
conn.rollback()
finally :
if conn :
conn.close()
By using cur.execute() I have been able to verify that the above is successfully connecting to the database, and that I can query against it. However, I have thus far been unable to successfully call a stored procedure with parameters.
The documentation here(possibly out of date?) indicates that callproc() can be called with either a string or a tuple to identify the procedure. The example given -
c.callproc(("northwind", "dbo", "SalesByCategory"), ["Seafood", "1998"], maxrows=2)
When I attempt to use this method, I receive the following error
Error("Could not find stored procedure 'CSM.DUMMY'. [SQLCode: 2812], [SQLState: S00062]",)
It would appear that zxJDBC is neglecting to include the dbo part of the procedure identifier.
If I instead call callproc with "CSM.dbo.DUMMY" as the first argument then I receive this error
Error('An object or column name is missing or empty. For SELECT INTO statements, verify each column has a name. For other statements, look for empty alias names. Aliases defined as "" or [] are not allowed. Change the alias to a valid name. [SQLCode: 1038], [SQLState: S0004]',)
Using a profiler on the database whilst running my script shows that in the second case the following SQL is executed:
use []
go
So it would seem that when using a single string to identify the procedure, the database name is not correctly parsed out.
One of my trial and error attempts to fix this was to call callproc as follows:
cur.callproc(('CSM', '', 'dbo.DUMMY'), ['carrier1'])
This got me only as far as
Error("Procedure or function 'DUMMY' expects parameter '#carrierId', which was not supplied. [SQLCode: 201], [SQLState: S0004]",)
In this case what I think is happening is that zxJDBC attempts to call a system stored procedure (sp_proc_columns) to determine the required parameters for the stored procedure I want to call. My guess is that with the procedure identifier in the incorrect format above, zxJDBC does not get a valid/correct return and assumes no parameters are required.
So basically I am not a bit stuck for ideas as to how to get it to
Use the correct database name
Correctly determine the required parameters using sp_proc_columns
Call my stored procedure with the correct name
all at the same time.
I do have a workaround, which is to use something like
cur.execute('EXEC CSM.dbo.DUMMY ?', ['carrier1'])
However I feel like callproc() is the correct solution, and would likely produce cleaner code when I come to call stored procedures with large numbers of parameters.
If anyone can spot the mistake(s) that I am making, or knows that this is not ever going to work as I think then any input would be much appreciated.
Thanks
Edit
As suggested by i-one, I tried adding cur.execute('USE CSM') before calling my stored procedure (also removing the database name from the procedure call). This unfortunately produces the same Object or Column missing error as above. The profiler shows USE CSM being executed, followed by USE [] so it seems that callproc() always fires a USE statement before the procedure itself.
I have also experimented with turning on/off autocommit, to no avail.
Edit 2
Further information following comments/suggested solutions:
"SQLEXPRESS" in my connection string is the database instance name.
Using double quotes instead of single has no effect.
Including the database name in the connection string (via ;databaseName=CSM; as specified here) and omitting it from the callproc() call leads to the original error with a USE [] statement being fired.
Using callproc(('CSM', 'dbo', 'dbo.DUMMY'), ['carrier1']) gives me some progress but results in the error
Error("Procedure or function 'DUMMY' expects parameter '#carrierId', which was not supplied. [SQLCode: 201], [SQLState: S0004]",)
I'll attempt to investigate this further
Edit 3
Based on the queries I could see zxJDBC firing, I manually executed the following against my database:
use CSM
go
exec sp_sproc_columns_100 N'dbo.DUMMY',N'dbo',N'CSM',NULL,N'3'
go
This gave me an empty results set, which would seem to explain why zxJDBC isn't passing any parameters to the stored procedure - it doesn't think it needs to. I have yet to figure out why this is happening though.
Edit 4
To update the above, the empty result set is because the call should be
exec sp_sproc_columns_100 N'DUMMY',N'dbo',N'CSM',NULL,N'3'
This unfortunately brings me full circle as I can't remove the dbo owner from the stored procedure name in my callproc() call or the procedure won't be found at all.
Edit 5
Table definition as requested
CREATE TABLE [dbo].[carrier](
[carrierId] [varchar](50) NOT NULL,
[test] [varchar](50) NULL
) ON [PRIMARY]
Though completely unaware of the technologies used here (unless some minor knowledge of SQL Server), I will attempt an answer (please forgive me if my jython syntax is not correct. I am trying to outline possibilities here not exact code)
My first approach (found at this post) would be to try:
cur.execute("use CSM")
cur.callproc(("CSM","dbo","dbo.DUMMY"), ["carrier1"])
This must have to do with the fact that sa users always have the dbo as a default schema (described at this SO post)
If the above does not work I would also try to use the CSM database name in the JDBC url (this is very common when using JDBC for other databases) and then simply call one of the two below.
cur.callproc("DUMMY", ["carrier1"])
cur.callproc("dbo.DUMMY", ["carrier1"])
I hope this helps
Update: I quote the relevant part of the link that you can't view
>> Program calls a Stored Procedure - master.dbo.xp_fixeddrives on MS SQL Server
from com.ziclix.python.sql import zxJDBC
def getConnection():
url = "${DBServer.Url}"
user= "${DBServer.User}"
password = "${DBServer.Password}"
driver = "${DBServer.Driver}"
con = zxJDBC.connect(url, user, password, driver)
return con
try:
conn = getConnection()
print 'Connection successful'
cur = conn.cursor()
cur.execute("use master")
cur.callproc(("master", "dbo", "dbo.xp_fixeddrives"))
print cur.description
for a in cur.fetchall():
print a
finally:
cur.close()
conn.close()
print 'Connection closed'
The error you get when you specified the call function like above suggests that the parameter is not passed correctly. So please modify your stored procedure to take a default value and try to call with passing params = [None]. If you see that the call succeeds we must have done something right as far as specifying the database is concerned.
Btw: the most recent documentation suggests that you should be able to access it with your syntax.
As outlined in comments callproc will work only with SELECT. Try this approach instead:
cur.execute("exec CSM.dbo.DUMMY #Param1='" + str(Param1) + "', #carrierId=" + str(carrierID))
Please see this link for more detail.
I'm getting a "play.exceptions.JavaExecutionException:
ColumnNotFound(comments.id)" in a piece of code after trying to
migrate to MySql instead of the memorydb. Postgres support by Magic is
almost null.
The evolution:
create table comments (
id bigint(20) NOT NULL AUTO_INCREMENT,
source varchar(255) NOT NULL,
target varchar(255) NOT NULL,
content text NOT NULL,
date bigint NOT NULL,
PRIMARY KEY (id)
);
The model:
case class comments(id: Pk[Long], source: String, target: String,
content: String, date: Long) {
override def toString = "|%s| |%s|, |%s|, |%s|".format(id.toString,
source, target, content)
lazy val formattedDate = new SimpleDateFormat("dd.MM.yyyy HH:mm")
format date
}
object comments extends Magic[comments]
And the piece of code:
def loadComments(username: String) = SQL("""select c.*, u.* from
comments c, usr u where c.source = u.ccall and c.target = {ccall}
order by c.date desc""").on("ccall" -> username).as(comments ~< usr *)
Can anyone give me some pointers? I'm really stuck on this.. Here is the stacktrace:
play.exceptions.JavaExecutionException: ColumnNotFound(comments.id)
at play.mvc.ActionInvoker.invoke(ActionInvoker.java:228)
at Invocation.HTTP Request(Play!)
Caused by: java.lang.RuntimeException: ColumnNotFound(comments.id)
at scala.Predef$.error(Predef.scala:58)
at play.db.anorm.Sql$.as(Anorm.scala:984)
at play.db.anorm.Sql$class.as(Anorm.scala:919)
at play.db.anorm.SimpleSql.as(Anorm.scala:829)
at controllers.Profile$.loadacomments(Profile.scala:21)
at controllers.Profile$.loadacommentsWithLikes(Profile.scala:46)
at controllers.Profile$.comment(Profile.scala:91)
at play.mvc.ActionInvoker.invokeWithContinuation(ActionInvoker.java:543)
at play.mvc.ActionInvoker.invoke(ActionInvoker.java:499)
at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:493)
at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:470)
at play.mvc.ActionInvoker.invoke(ActionInvoker.java:158)
Thank you!
On this specific case, the mysql driver was an old one that made the names look really strange. I just updated the driver and everything came back to place.
You can check the thread in google groups here: http://groups.google.com/group/play-framework/browse_thread/thread/3bd8d3ccb5a51d10/e7074ad34ac637da?lnk=gst&q=Jos%C3%A9+Leal#e7074ad34ac637da
I assume that comments magic works for trivial queries? Have you tried not aliasing the table?
If that fails, I have a fairly hackish solution to it. Which is how I'm using Anorm with Postgres. I had to edit the Anorm source code to look for just the <column name> and not <table name>.<column name>. But that brings along a the problem that Anorm can't identify which column is which in a JOIN. So I had to resort to naming all my columns uniquely.
Alternatively, you could try pulling the latest play-scala code from github, but I don't know if there's any significant progress regarding this issue.
Not sure, but I've seen it where when you query multiple tables with Table1., Table2., and they BOTH have a column by the same name... such as "ID", then they get returned as
ID_A, ID_B, etc... then the other columns. So, if your USR table has a column called "ID" also, then this might be what you are running into.
If so, you could either explicitly list all the columns from the USR table and NOT include that table's ID column...
OR
add a column to your query
select C.ID as MyCTableID, C., U. ...
Then, you KNOW you will explicitly have a column called "MyCTableID" to run with.