I have a Select query which selects the top 10 values from table
Create proc [dbo].[SP_Select_Top10]
as
select DISTINCT top (10)
Score, FBid
from
FB_Player
ORDER BY
Score DESC
What I need is to have the results of this query in xml file as.
<player>
<name> </name>
<score> </score>
</player>
I use ASP.NET to create this file how can I do that ?
Create your stored procedure like this - use the FOR XML PATH(), ROOT() syntax to have SQL Server generate a proper XML for you:
CREATE PROCEDURE dbo.procGetPlayerScore
AS BEGIN
SELECT DISTINCT TOP (10)
ID AS '#ID', -- creates an attribute on the <Player> node
Name, -- gets output as element inside <Player>
Score -- gets output as element inside <Player>
FROM
dbo.FB_Players
ORDER BY
Score DESC
FOR XML PATH('Player'), ROOT('AllPlayers')
END
In your C# code, you need something like this - connect to the database, execute the stored procedure, get back the single row, single column of that stored procedure (the XML produced):
// set up SQL Server connection and command to execute the stored procedure
using(SqlConnection conn = new SqlConnection("server=.;database=test;Integrated Security=SSPI"))
using (SqlCommand cmdGetPlayers = new SqlCommand("dbo.procGetPlayerScore", conn))
{
// define that it's a stored procedure
cmdGetPlayers.CommandType = CommandType.StoredProcedure;
// open connection, execute procedure, get resulting XML, close connection
conn.Open();
string playersXml = cmdGetPlayers.ExecuteScalar().ToString();
conn.Close();
}
As result, you'll get a XML something like this:
<AllPlayers>
<Player ID="4">
<Name>Player 4</Name>
<Score>72.1500</Score>
</Player>
<Player ID="1">
<Name>Player 1</Name>
<Score>50.5000</Score>
</Player>
......
</AllPlayers>
I would suggest looking at the native XML options of SQL Server
Link here
Also please note
<player>
<playername="" score="" />
</player>
is not valid xml, it would have to something like
<player name="" score="" />
or
<player>
<name></name>
<score></score>
</player>
depending on whether you want to be element-centric or attribute-centric, but all of these can be specified in the SQL server XML output options. Then you could just get the ASP.NET side to save the resulting query as a file.
Related
I have a stored function that generates an identity name based on a set of parameters like this:
.create function
with (docstring = 'Returns the table name for the specified data log provider.')
GetTableName(param1: string, param2: string)
{
// Some string cleansing and concatenation
let tableName = strcat(system, source);
tableName
}
I want to use this function to create a table. Tried the following options with no success:
.create table GetTableName('value1', 'value2') (Timestamp: datetime)
.create table [GetTableName('value1', 'value2')] (Timestamp: datetime)
I'm guessing the command expects the table name to be a string literal. Is there any way to accomplish this?
Control commands that create tables cannot include query execution (and vise versa: queries cannot run control commands).
The restriction exists for security reasons.
You can achieve the scenario using client code and having two calls:
1) Derive table name
2) Generate table create command and send it to the server.
how to manage the result of a query that returns an integer "select count(*) from table"?
1) I've tried to bind the output of a SQL Execute Statement service to an integer variable and doesn't work. (type mistmatch)
2) i've tried to use types like 'SQLResult', SQLResultRow, SQLResultColumn as well but they dont work:
Caused by: com.lombardisoftware.core.TeamWorksException: Type ismatch the value "[Element: ]" must be and instance of type atructured IBM BPM Java Class found: org.jdom.Element
3) i've tried to bind the output to a XMLElement variable and i've got this value
< resultSet recordCount=\"1\" columnCount=\"1\">5< /columnn>< /record>< /resultSet>
so now... how can I access the recordCount attribute of this node?
anyway, I don't like so manipulate a variable of XMLType, when are the types SQLResult, SQLResultRow, SQLResultColumn used?
****** EDITED *******
even if i get a result as XMLElement.. i can't manipulate it.
methods like: tw.local.result[0].rows[0].column[0].getText() don't work (the intellisense as well)
the XMLElement as an attribute "recordCount" but i don't know how to get his value..
Anyway, the only workaround that i found is to change the query in order to return a normal set of records(not a scalar value)
select field from table instead of select count(field) from table
so i could to map the output value to a list of objects and than count its length...
ugly and dirty :-(
anyone know how manipulate the XMLElement in a script block?
Please try this.
Bind the output variable from sql execute statement as 'ANY' type.
variable name - result (ANY)
Query - select count(field) as COUNTVAL from table
tw.local.totalCount = tw.local.result[0].rows[0].indexedMap.COUNTVAL;
Use Return type as XMLElement then bind a XMLElement in output mapping.
For eg: If you are using tw.local.output as ouput mapping (of type XMLElement) then,
log.info("Count "+tw.local.output.xpath('/resultSet/record/column').item(0).getText());
This will print the count
If you want to get "recordCount" Attribute then use
tw.local.output.getAttribute("recordCount");
I'm trying to implement a Guice module that to lets Guacamole use SQLite as a backend. The Guacamole project has a generic JDBC base module. This lets you implement modules for specific datastores with less code. Most of the lines of code end up being in mapper XML files. The project provides PostgreSQL and MySQL implementations.
I based this SQLite module off of the MySQL module. For the mapper XML files, SQLite and MySQL are similar enough that I didn't have to make any changes. However, when I try to use the SQLite module, I get this error:
### Error querying database. Cause: java.lang.ArrayIndexOutOfBoundsException: 2
### The error may exist in org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: SELECT guacamole_connection_group.connection_group_id, connection_group_name, parent_id, type, max_connections, max_connections_per_user, enable_session_affinity FROM guacamole_connection_group JOIN guacamole_connection_group_permission ON guacamole_connection_group_permission.connection_group_id = guacamole_connection_group.connection_group_id WHERE guacamole_connection_group.connection_group_id IN ( ? ) AND user_id = ? AND permission = 'READ'; SELECT parent_id, guacamole_connection_group.connection_group_id FROM guacamole_connection_group JOIN guacamole_connection_group_permission ON guacamole_connection_group_permission.connection_group_id = guacamole_connection_group.connection_group_id WHERE parent_id IN ( ? ) AND user_id = ? AND permission = 'READ'; SELECT parent_id, guacamole_connection.connection_id FROM guacamole_connection JOIN guacamole_connection_permission ON guacamole_connection_permission.connection_id = guacamole_connection.connection_id WHERE parent_id IN ( ? ) AND user_id = ? AND permission = 'READ';
### Cause: java.lang.ArrayIndexOutOfBoundsException: 2
It looks like the problem is that two parameters are passed to the query, but each is repeated three times. When MyBatis generates the PreparedStatement, it acts as if there are six parameters that needed to be passed in.
Here's the query it has a problem with:
<!-- Select multiple connection groups by identifier only if readable -->
<select id="selectReadable" resultMap="ConnectionGroupResultMap"
resultSets="connectionGroups,childConnectionGroups,childConnections">
SELECT
guacamole_connection_group.connection_group_id,
connection_group_name,
parent_id,
type,
max_connections,
max_connections_per_user,
enable_session_affinity
FROM guacamole_connection_group
JOIN guacamole_connection_group_permission ON guacamole_connection_group_permission.connection_group_id = guacamole_connection_group.connection_group_id
WHERE guacamole_connection_group.connection_group_id IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = 'READ';
SELECT parent_id, guacamole_connection_group.connection_group_id
FROM guacamole_connection_group
JOIN guacamole_connection_group_permission ON guacamole_connection_group_permission.connection_group_id = guacamole_connection_group.connection_group_id
WHERE parent_id IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = 'READ';
SELECT parent_id, guacamole_connection.connection_id
FROM guacamole_connection
JOIN guacamole_connection_permission ON guacamole_connection_permission.connection_id = guacamole_connection.connection_id
WHERE parent_id IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = 'READ';
</select>
If I manually populate the parameters, I can execute this against the SQLite database. Also, the MySQL version works fine.
What the heck is going on? What can I do to debug this? Is it a MyBatis problem or something with the JDBC connector?
If it helps, you can see the code for the module here.
Here's the method for the parameter the mapper related to this query. The full mapper classes for ConnectionGroup are here and here. The full mapper XML for my SQLite module is here.
Collection<ModelType> selectReadable(#Param("user") UserModel user,
#Param("identifiers") Collection<String> identifiers);
This is what the ConnectionGroupResultMap looks like:
<resultMap id="ConnectionGroupResultMap" type="org.apache.guacamole.auth.jdbc.connectiongroup.ConnectionGroupModel" >
<!-- Connection group properties -->
<id column="connection_group_id" property="objectID" jdbcType="INTEGER"/>
<result column="connection_group_name" property="name" jdbcType="VARCHAR"/>
<result column="parent_id" property="parentIdentifier" jdbcType="INTEGER"/>
<result column="type" property="type" jdbcType="VARCHAR"
javaType="org.apache.guacamole.net.auth.ConnectionGroup$Type"/>
<result column="max_connections" property="maxConnections" jdbcType="INTEGER"/>
<result column="max_connections_per_user" property="maxConnectionsPerUser" jdbcType="INTEGER"/>
<result column="enable_session_affinity" property="sessionAffinityEnabled" jdbcType="BOOLEAN"/>
<!-- Child connection groups -->
<collection property="connectionGroupIdentifiers" resultSet="childConnectionGroups" ofType="java.lang.String"
column="connection_group_id" foreignColumn="parent_id">
<result column="connection_group_id"/>
</collection>
<!-- Child connections -->
<collection property="connectionIdentifiers" resultSet="childConnections" ofType="java.lang.String"
column="connection_group_id" foreignColumn="parent_id">
<result column="connection_id"/>
</collection>
</resultMap>
David,
I know this is a little old, but I'm also trying to implement a SQLite JDBC module, and ran into exactly the same problem. I've managed to track down the source of the issue, and have filed an issue on the JDBC SQLite github page:
https://github.com/xerial/sqlite-jdbc/issues/277
Basically, the SQLite JDBC driver computes one of its array sizes based on the parameter count for a prepared statement. However, in the cases you mentioned, there are multiple SELECT statements which take the same parameters, so the array needs to be x * y (x = parameter count, y = number of select statements) rather than just the number of parameters. When it tries to prepare the statement, it hits the first position beyond the parameter count and generates this exception.
The other JDBC modules - MySQL, PostgreSQL, and SQL Server, as well as Oracle and H2 that I'm messing with - seem to handle this situation correctly (well, Oracle is a little...special...), but the SQLite driver does not.
I was able to work around the issue in a really, really kludgy way, by creating two different result maps, one for the generic select and one for the read that checks for READ permissions, and then break out each of the select queries into its own SELECT block and call those from the collection inside the result map. It's nowhere near as elegant as the existing code, but it works.
I got stored function which returns query. In ASP project I got GridView which I bind to SqlDataSource element (it named SqlDataProjectWells).
So, when I try to call it there are error appears which says something like
"error while trying to execute query"
But in pgAdmin select command works perfectly
Code calls on page load
void bindToTable(){
SqlDataProjectWells.SelectCommand = "SELECT get_zonetable()";
SqlDataProjectWells.Select(DataSourceSelectArguments.Empty);
myGridView.DataBind();
}
Stored procedure code
CREATE OR REPLACE FUNCTION get_ZoneTable()
RETURNS SETOF RECORD
AS
$$
BEGIN
return QUERY SELECT "WELLS".well_name, "ZONES".id_zones, "ZONES".top, "ZONES".botom FROM "WELLS" LEFT JOIN "ZONES" ON "WELLS".well_id = "ZONES".id_well;
/*RETURN;*/
--return result_record;
END
$$ LANGUAGE plpgsql;
Whats wrong?!
UPD:
If I use stored procedure - there are such error appears
ERROR [0A000] Error while executing the query
If I use select like this
SqlDataProjectWells.SelectCommand = "SELECT \"WELLS\".well_name, \"ZONES\".id_zones, \"ZONES\".top, \"ZONES\".botom FROM \"WELLS\" LEFT JOIN \"ZONES\" ON \"WELLS\".well_id = \"ZONES\".id_well;"
It caused error which says
A field or property with the name 'id_well' was not found on the
selected data source
Shouldn't you be calling DataBind on the GridView instead of the SqlDataSource?
Well, kinda solved problem this way. Stored procedure creates all_zones view which I use aftel in ASP code like SqlDataProjectWells.SelectCommand = "SELECT * FROM all_zones";
Stored procedure text
CREATE OR REPLACE FUNCTION get_zones_view()
RETURNS void AS
$BODY$
DECLARE
BEGIN
execute 'CREATE OR REPLACE VIEW "all_zones" AS SELECT "WELLS".well_name, "ZONES".id_zones, "ZONES".top, "ZONES".botom FROM "ZONES" JOIN "WELLS" ON "WELLS".well_id = "ZONES".id_well';
END;
$BODY$
LANGUAGE plpgsql
but I assume that it's not okay to do like that
I'm attempting to setup a search function from a string a user types. (ex: "John Doe" or "Doe, John")
I was thinking I would use Replace(SearchString, ",", "") to get rid of the commas the user might enter, and then use Split(SearchString, " ") to get all the words into an array. Once they're in the array I would execute a Stored Procedure on each of the terms and build a DataTable with the results.
Below is what I'm wanting to use for executing my stored procedure.
oCommand = DataAccess.GetSQLCommand("MyStoredProcedure", CommandType.StoredProcedure, SourceServer.ConnectionLocal)
oCommand.Parameters.AddWithValue("#MySearchString", SearchString)
oAdapter = New SqlDataAdapter(oCommand)
oAdapter.Fill(MyDataTable)
Now I'm thinking the "SearchString" I will assign while looping through my array of words... but this doesn't seem like the right way to do this. Maybe it is but I don't know how to append my next result to the previous DataTable either.
There are some great ideas for using arrays and Lists in SQL Server on this page - http://www.sommarskog.se/arrays-in-sql-2005.html
I personally find the XML method the most useful;
http://www.sommarskog.se/arrays-in-sql-2005.html#XML
An example of how I've used this in the past is;
DECLARE #indata nvarchar(max)
DECLARE #hDoc int
SET #indata = '
<ROOT>
<SearchTerm code="Test search term"></SearchTerm>
<SearchTerm code="Other search term"></SearchTerm>
<SearchTerm code="Next search term"></SearchTerm>
</ROOT>'
CREATE TABLE #searchTerm (
code varchar(40)
)
EXEC sp_xml_preparedocument #hDoc OUTPUT, #indata
INSERT Into #searchTerm
SELECT code
FROM OPENXML(#hDoc, '/ROOT/SearchTerm',1)
WITH (code varchar(50))
EXEC sp_xml_removedocument #hDoc
-- Use the data in #searchTerm as needed in your query
SELECT * FROM MyTable WHERE searchValue IN (SELECT code FROM #searchTerm)
DROP TABLE #searchTerm
Try passing in the comma separated values in as a single string of nvarchar. Then use the SELECT FROM WHERE IN structure within your stored procedure. Create the sql command wwithin your stored procedure by concatenation and then call EXEC #sql
Declare #sql =
'SELECT * FROM tbl
WHERE person IN(' + #Application + ')'
exec(#sql)
Beware, if your list of search criteria is large this may not be the best solution for you.
Note that the commas should be between the full names not the first name and last name.