Reputation: 51
I'm currently retrieving a set of values using a loop of queries. The problem is that some queries are JOIN sentences that return a set of values instead of single one and thus ExecuteScalar method won't work for me.
This is my loop.
'allQueries' is a List of class 'Queries' (Properties: name, db_engine, query) that contains every SQL query that is going to be used.
'queryData' is a Dictionary that will be filled with the results of all the queries.
using( SqlConnection connection = new SqlConnection( builder.ConnectionString ) )
{
try { connection.Open(); } catch( Exception ex ) { Console.WriteLine( "[" + DateTime.Now + "] ERROR: " + ex.Message ); }
Dictionary<string, string> queryData = new Dictionary<string, string>();
foreach( dynamic query in allQueries )
{
// Execute every query and fill the 'queryData' Dictionary with the results of each one.
SqlCommand cmd = new SqlCommand( query.query, connection);
try
{
queryData.Add( query.name, Convert.ToString( cmd.ExecuteScalar() ) );
}
catch( Exception ex )
{
Console.WriteLine( "[" + DateTime.Now + "] ERROR: " + ex.Message );
Console.WriteLine( "[" + DateTime.Now + "] DEBUG: Query <<" + query.name + ">>" );
}
}
}
This is an example of one of the queries that return a set of values, it basically returns a 3 column table with 10 rows (It's SQL Server 2008 R2):
BEGIN
DECLARE @LunesSem0 DATETIME
DECLARE @DomSem0 DATETIME
SET @LunesSem0 = DATEADD( HOUR, 6, DATEADD(wk, DATEDIFF(wk, 0, CURRENT_TIMESTAMP), 0) )
SET @DomSem0 = DATEADD( SECOND, -1, DATEADD(HOUR, 6, DATEADD(wk, DATEDIFF(wk, 0,
CURRENT_TIMESTAMP), 7) ) )
END
SELECT TOP 10 productos.descripcion AS descripcion,
sum(cheqdet.cantidad) AS cantidad,
sum(cheqdet.cantidad * (cheqdet.precio - (cheqdet.precio * (cheqdet.descuento/100)))) AS monto
FROM productos
INNER JOIN cheqdet ON cheqdet.idproducto = productos.idproducto
INNER JOIN grupos ON productos.idgrupo = grupos.idgrupo
WHERE grupos.clasificacion = '2' AND cheqdet.hora BETWEEN @LunesSem0 AND @DomSem0
GROUP BY cheqdet.idproducto,productos.descripcion
ORDER BY cantidad DESC
I need the program to get that set of values and turn them into a JSON so it can fit in a single value in its corresponding cell in queryData. If there's a solution in SQL that'll work for me too.
Thanks in advance
Upvotes: 0
Views: 310
Reputation: 51
I managed to work around the problem.
After some research I found out that while Microsoft SQL Server 2008 doesn't support the FOR JSON sentence, it does support FOR XML and that makes things a lot easier.
First I added this line at the end of the SQL queries that returned a result set:
FOR XML RAW, ROOT('productos')
Then I edited my code like this. I reorganized it to put the connection sentence inside the loop, fixing the "Open DataReader" error. Then I validated the result in each iteration to see if the value started with a "<" indicating an XML value (I know there must be a less silly solution for this 😅, I'll see that later). That way I could perform an XML to JSON conversion only when needed.
// Start a loop through all the rows in 'allQueries'
foreach( dynamic query in allQueries )
{
// Open up a SQL Connection
using( SqlConnection connection = new SqlConnection( builder.ConnectionString ) )
{
// Attempt to open it.
try { connection.Open(); } catch( Exception ex ) { Console.WriteLine( "[" + DateTime.Now + "] ERROR abriendo conexión a base de datos local: " + ex.Message ); }
// Build an SQL command
using( SqlCommand cmd = new SqlCommand(query.query, connection) )
{
try
{
String tempResult = Convert.ToString(cmd.ExecuteScalar());
// Validate if the current result is an XML value using a cheap first character comparison.
if( tempResult.Substring(0,1) == "<" )
{
// Prepare an XmlDocument with the result of the current iteration.
XmlDocument xmlResult = new XmlDocument();
xmlResult.LoadXml( tempResult );
// Convert XML to JSON
String jsonResult = JsonConvert.SerializeXmlNode( xmlResult );
// Add the converted result to the 'queryData' Dictionary
queryData.Add( query.name, jsonResult );
//Console.WriteLine( "[" + DateTime.Now + "] Query <<" + query.name + ">> con el valor: " + Convert.ToString( cmd.ExecuteScalar() ) );
}
else
{
// If the current result is not an XML value just add it to the 'queryData' Dictionary.
queryData.Add( query.name, tempResult );
}
}
catch( Exception ex )
{
Console.WriteLine( "[" + DateTime.Now + "] ERROR: " + ex.Message );
Console.WriteLine( "[" + DateTime.Now + "] ON QUERY <<" + query.name + ">>" );
}
}
connection.Close();
}
}
This took me the whole day, I'll go lay down for a bit... I hope this will be helpful for someone.
Upvotes: 1