SQL : recursive looping - sql

Table is as follows:
I'm trying to get the result set to have groups of all person that intersects from the table, hence creating following groups in result set from attached table.
Person1, Person2, Person3, Person7, Person8
Person5, Person6, Person9
So far I have following query, but can't seem to get the results intersected on a table of rows and outputted as 1 column.
DECLARE #r VARCHAR(MAX), #n INT, #i INT
SELECT #i = 1,
#r = 'SELECT BOX, ' + CHAR(13),
#n = (SELECT TOP 1 COUNT( USERS )
FROM EXCHANGE
GROUP BY BOX
ORDER BY COUNT( USERS ) DESC ) ;
WHILE #i <= #n BEGIN
SET #r = #r +
CASE WHEN #i = 1
THEN 'MAX( CASE Seq WHEN ' + CAST( #i AS VARCHAR ) + '
THEN USERS
ELSE SPACE(0) END ) + ' + CHAR(13)
WHEN #i = #n
THEN 'MAX( CASE Seq WHEN ' + CAST( #i AS VARCHAR ) + '
THEN '', '' + USERS
ELSE SPACE(0) END ) ' + CHAR(13)
ELSE 'MAX( CASE Seq WHEN ' + CAST( #i AS VARCHAR ) + '
THEN '', '' + USERS
ELSE SPACE(0) END ) + ' + CHAR(13)
END ;
SET #i = #i + 1 ;
END
SET #r = #r + '
FROM ( SELECT BOX, USERS,
ROW_NUMBER() OVER ( PARTITION BY BOX ORDER BY USERS )
FROM EXCHANGE p ) D ( BOX, USERS, Seq )
GROUP BY BOX;'
EXEC( #r ) ;

This type of graph walking is a pain in SQL Server -- you have cycles. The problem is avoiding cycles. Because SQL Server doesn't have very good data types, you need to store the visited nodes as strings.
You can do all this in a recursive CTE. The idea is to follow all paths from a node without repeating any node. Keep the minimum node visited. Voila! That specifies the path:
with cte as (
select box, users,
convert(varchar(max), concat(',', box, ',', users, ',')) as path,
(case when box < users then box else users end) as min_node
from exchange
union all
select cte.box, e.users,
concat(cte.path, e.users, ','),
(case when min_node < e.users then min_node else e.users end)
from cte join
exchange e
on e.box = cte.users
where path not like '%,' + e.users + ',%'
)
select cte.box, min(cte.users), min(cte.path), min(cte.min_node) as grouping
from cte
group by cte.box;
Here is a db<>fiddle.
This assumes that the edges are symmetric, so if you have (a, b), you also have (b, a).
If this is not the case, it is easy to add a CTE that makes this the case:
select box, users
from exchange
union -- on purpose to remove duplicates
select users, box
from exchange;

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RecusriveGroup
{
public class FinalResult
{
public string GroupName { get; set; }
public string BoxName { get; set; }
public string UserName { get; set; }
}
class Program
{
static void Main(string[] args)
{
using(var con = new SqlConnection("Data Source=SQLServer;Initial Catalog=TESTDB;Integrated Security=SSPI"))
{
con.Open();
var cmd = new SqlCommand("select distinct Box from Exchange");
cmd.Connection = con;
var adapter = new SqlDataAdapter(cmd);
DataSet dsResult = new DataSet();
adapter.Fill(dsResult);
var finalResult = new List<FinalResult>();
var groupId = 0;
foreach (DataRow row in dsResult.Tables[0].Rows)
{
if(finalResult.Any(f => f.BoxName.Equals(row["Box"])))
{
continue;
}
groupId++;
RecursiveCall("Group" + groupId, row["Box"].ToString(), "", con, finalResult);
}
foreach(var result in finalResult)
{
var cmd1 = new SqlCommand("INSERT INTO FinalResult(Box, [User], [Group]) VALUES(#Box, #User, #Group)", con);
cmd1.Parameters.AddWithValue("#Box", result.BoxName);
cmd1.Parameters.AddWithValue("#User", result.UserName);
cmd1.Parameters.AddWithValue("#Group", result.GroupName);
cmd1.ExecuteNonQuery();
}
}
Console.ReadLine();
}
private static void RecursiveCall(string groupName, string boxName, string userName, SqlConnection sqlConnection, List<FinalResult> finalResult)
{
DataSet dsResult = new DataSet();
if (!string.IsNullOrEmpty(boxName) && !string.IsNullOrEmpty(userName))
{
var cmd = new SqlCommand("select Box, Users from Exchange WHERE Box = #BoxName OR Users = #UserName");
cmd.Parameters.AddWithValue("#BoxName", boxName);
cmd.Parameters.AddWithValue("#UserName", userName);
cmd.Connection = sqlConnection;
var adapter = new SqlDataAdapter(cmd);
adapter.Fill(dsResult);
}
else if(!string.IsNullOrEmpty(boxName))
{
var cmd = new SqlCommand("select Box, Users from Exchange WHERE Box = #BoxName");
cmd.Parameters.AddWithValue("#BoxName", boxName);
cmd.Connection = sqlConnection;
var adapter = new SqlDataAdapter(cmd);
adapter.Fill(dsResult);
}
else
{
var cmd = new SqlCommand("select Box, Users from Exchange WHERE Users = #UserName");
cmd.Parameters.AddWithValue("#UserName", userName);
cmd.Connection = sqlConnection;
var adapter = new SqlDataAdapter(cmd);
adapter.Fill(dsResult);
}
foreach (DataRow row in dsResult.Tables[0].Rows)
{
if (finalResult.Any(f => f.BoxName.Equals(row["Box"].ToString()) && f.UserName.Equals(row["Users"].ToString())))
{
continue;
}
finalResult.Add(new FinalResult() { GroupName = groupName, BoxName = row["Box"].ToString(), UserName = row["Users"].ToString() });
RecursiveCall(groupName, row["Box"].ToString(), row["Users"].ToString(), sqlConnection, finalResult);
}
}
}
}

Related

Apex - Test Batch class Execute method not covered code coverage

Batch apex class not covering execute method
Batch Apex Class : Trying to cover execute method but not covered in image above.
This batch class is on aggregate result. Please suggest me how to cover this batch class
It is working on search result of order if the status is based on filter then in execute method it will aggregate the value of fulfilment id of all orders related to it. based on their order status it executes.
global class UpdateOrderIntegrationStatus_Batch implements
Database.Batchable<AggregateResult>, Database.Stateful{
String status_filter = 'Waiting On Prior Order';
String query = 'select count(Id) cnt, Fulfillment__c from Apttus_Config2__Order__c'
+' where Fulfillment__c <> null and Order_Integration_Status__c = \''+status_filter + '\''
+' group by Fulfillment__c '
+' limit 50000';
public UpdateOrderIntegrationStatus_Batch(){}
public UpdateOrderIntegrationStatus_Batch(string q){
query = q;
}
global Iterable<AggregateResult> start(Database.BatchableContext BC){
//system.debug('>>>> query : ' + query)
return new AggregateResultIterable(query);
}
global void execute(Database.BatchableContext BC, List<sobject> results){
set<Id> fufillmentIds = new set<Id>();
for(Sobject sObj:results){
AggregateResult ar = (AggregateResult)sObj;
fufillmentIds.add((Id) ar.get('Fulfillment__c'));
}
List<Contract> fulfillments = [select id,(select Id, Order_Integration_Status__c from Orders__r order by Name asc) from Contract where id IN:fufillmentIds];
List<Apttus_Config2__Order__c> orderToUpdate = new List<Apttus_Config2__Order__c>();
String priorOrderIntegrationStatus = '';
for(Contract fulfillmentObj: fulfillments){
priorOrderIntegrationStatus = '';
for(Apttus_Config2__Order__c order: fulfillmentObj.Orders__r){
if(order.Order_Integration_Status__c == 'Processed'){
priorOrderIntegrationStatus = order.Order_Integration_Status__c;
}
else if(order.Order_Integration_Status__c == 'Error'){
break;
}
else if(order.Order_Integration_Status__c == status_filter && priorOrderIntegrationStatus == 'Processed' ){
order.Order_Integration_Status__c = 'Ready';
orderToUpdate.add(order);
priorOrderIntegrationStatus = order.Order_Integration_Status__c;
break;
}
else{
priorOrderIntegrationStatus = order.Order_Integration_Status__c; //For other statuses like Ready, Not Ready, Pending etc.
continue;
}
}
}
if(orderToUpdate <> null && orderToUpdate.size() > 0){
Database.update(orderToUpdate, false);
}
}
global void finish(Database.BatchableContext BC){
System.debug('UpdateOrderIntegrationStatus_Batch Finished');
}
}
Test Batch class:
#isTest
public class UpdateOrderIntegrationStatus_Batch_Test {
public static testMethod void testBatch() {
Test.StartTest();
Account acc =APTS_BvdUtility.createAccount();
Contact con = APTS_BvdUtility.createContact(acc.Id);
Apttus_Config2__AccountLocation__c acclocation = APTS_BvdUtility.createAccountLocation('Test Loc', acc.Id, con.Id);
Opportunity opp = APTS_BvdUtility.createOpportunity('Test Opp ', acc.Id, con.Id);
Apttus_Config2__PriceList__c priceList = APTS_BvdUtility.createPriceList('Test PriceBook') ;
Apttus_Proposal__Proposal__c quote = APTS_BvdUtility.createQuote(acc, opp, priceList.Id, 'quoteName');
Apttus_Config2__Order__c newOrder = new Apttus_Config2__Order__c();
newOrder.Apttus_QPConfig__ProposalId__c = quote.Id;
newOrder.Apttus_Config2__Status__c = 'Pending';
newOrder.AC_Billing_Street_1__c = '234';
newOrder.AC_Shipping_Street_1__c = '234';
newOrder.Ultimate_Parent_Account_ID__c = quote.Apttus_Proposal__Account__c;
newOrder.Apttus_Config2__BillToAccountId__c = quote.Apttus_Proposal__Account__c;
newOrder.Apttus_Config2__ShipToAccountId__c = quote.Apttus_Proposal__Account__c;
newOrder.Apttus_Config2__RelatedOpportunityId__c = quote.Apttus_Proposal__Opportunity__c;
newOrder.Apttus_Config2__OrderStartDate__c = quote.Apttus_Proposal__ExpectedStartDate__c;
newOrder.Apttus_Config2__OrderEndDate__c = quote.Apttus_Proposal__ExpectedEndDate__c;
newOrder.Apttus_Config2__SoldToAccountId__c = quote.Apttus_Proposal__Account__c;
newOrder.Apttus_Config2__PriceListId__c = quote.Apttus_QPConfig__PriceListId__c;
newOrder.Apttus_Config2__Type__c = quote.Apttus_QPConfig__ABOType__c;
newOrder.Language__c = 'English';
newOrder.Billing_Cycle__c = 'Annual';
newOrder.Detailed_Invoice__c = true;
newOrder.Bill_To_Contracting_Party__c = 'Test123';
newOrder.Ship_To_Contracting_Party__c = 'Test123';
newOrder.Bill_To_Location__c = acclocation.Id;
newOrder.Ship_To_Location__c = acclocation.id;
newOrder.Bill_To_Ultimate_Parent_Account_ID__c = quote.Apttus_Proposal__Account__c;
newOrder.Ship_To_Ultimate_Parent_Account_ID__c = quote.Apttus_Proposal__Account__c;
newOrder.Apttus_Config2__ActivatedDate__c = System.today();
newOrder.Apttus_Config2__OrderDate__c = System.today();
newOrder.CurrencyIsoCode = quote.CurrencyIsoCode;
newOrder.Apttus_Config2__ActivatedDate__c = System.Date.today();
newOrder.Order_Integration_Status__c='Waiting On Prior Order';
insert newOrder;
String testseqname = 'CONTRACT_NUMBER';
double testseqnumber = 1234;
Sequence_Number__c sn = new Sequence_Number__c(Name = testseqname, Next_Sequence_Number__c = testseqnumber);
insert sn;
List<SObject> contracts = new List<Contract>();
Contract fulfillment = new Contract();
fulfillment.Fulfillment_Total__c = 6000;
fulfillment.AccountId = acc.Id;
fulfillment.Opportunity__c = opp.Id;
fulfillment.Renewal_Opportunity__c = opp.Id;
fulfillment.CurrencyIsoCode = newOrder.CurrencyIsoCode;
fulfillment.CustomerSignedDate = system.today();
fulfillment.Status = 'Client Signed';
fulfillment.End_Date__c = newOrder.Apttus_Config2__OrderEndDate__c;
fulfillment.StartDate = newOrder.Apttus_Config2__OrderStartDate__c;
fulfillment.Latest_Order__c = newOrder.Id;
fulfillment.Billing_Integration_Status__c = 'Ready';
fulfillment.RecordTypeId = System.Label.Sales_Contract_RecordTypeID;
fulfillment.Original_Order_Submit_Date__c = newOrder.Apttus_Config2__ActivatedDate__c.date();
fulfillment.BusinessUnit__c = 'Bureau van Dijk Electronic Publishing Inc.';
fulfillment.Contract_Sequence_Number__c = 993360;
// insert fulfillment;
contracts.add(fulfillment);
insert contracts;
List<Contract> contrList = [select id,(select Id, Order_Integration_Status__c from Orders__r order by Name asc) from Contract where id =:contracts[0].Id];
newOrder.Order_Integration_Status__c='Processed';
update newOrder;
String status_filter = 'Waiting On Prior Order';
String query = 'select count(Id) cnt, Fulfillment__c from Apttus_Config2__Order__c'
+' where Fulfillment__c <> null and Order_Integration_Status__c = \''+status_filter + '\''
+' group by Fulfillment__c '
+' limit 50000';
/* String query = 'select id,(select Id, Order_Integration_Status__c from Orders__r order
by Name asc) from Contract';
String query = 'select count(Id) cnt, Fulfillment__c from Apttus_Config2__Order__c'
+' where Fulfillment__c =\''+contrList[0].Id +'\' and Order_Integration_Status__c =
\''+status_filter + '\''
+' group by Fulfillment__c '
+' limit 50000';
*/
UpdateOrderIntegrationStatus_Batch obj = new UpdateOrderIntegrationStatus_Batch();
UpdateOrderIntegrationStatus_Batch obj1 = new UpdateOrderIntegrationStatus_Batch(query);
// obj1.execute(BC, contracts);
ID batchprocessid = Database.executeBatch(obj);
ID batchprocessid1 = Database.executeBatch(obj1,10);
List<Apttus_Config2__Order__c> orders =[select Id,
Order_Integration_Status__c,Fulfillment__c from Apttus_Config2__Order__c where
Fulfillment__c=:contracts[0].Id];
for(Apttus_Config2__Order__c ord : orders){
system.assertEquals('Processed', ord.Order_Integration_Status__c);
}
Test.StopTest();
}
}

SQL Select XML from table like serialized Dictionary<string, object)

I have an XML structure that I got by serializing a Dictionary in C#. I'm doing this to add one AdditionalSettings column to a table versus multiple additional columns and this works great.
The XML structure is like this:
<Settings xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Setting>
<Name>Setting1</Name>
<Value xmlns:d3p1="http://www.w3.org/2001/XMLSchema" i:type="d3p1:boolean">true</Value>
</Setting>
<Setting>
<Name>Setting2</Name>
<Value xmlns:d3p1="http://www.w3.org/2001/XMLSchema" i:type="d3p1:boolean">true</Value>
</Setting>
The table has several columns like this:
ID (INT)
Setting1 (BIT)
Setting2 (BIT)
I think I am close to a solution. This is the SQL that I have. The problem is that I am not getting the namespaces on the Value element.
WITH XMLNAMESPACES ('http://www.w3.org/2001/XMLSchema-instance' AS i)
SELECT TOP 1 'Setting1' AS [Setting/Name],
CASE Setting1 WHEN 1 THEN 'true' ELSE 'false' END AS [Setting/Value]
FROM MyTable
FOR XML PATH('Settings')
The output of this SQL looks like this:
<Settings xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Setting>
<Name>Setting1</Name>
<Value>true</Value>
</Setting>
</Settings>
EDIT: Instead of doing SQL for a fake table, I've created SQL for a Temp Table that shows what I am trying to do.
DECLARE #TestTable TABLE (ID INT IDENTITY(1, 1) PRIMARY KEY, [Name] VARCHAR(10), Setting1 BIT, Setting2 BIT)
INSERT INTO #TestTable (Name, Setting1, Setting2)
VALUES
('Test1', 0, 0),
('Test2', 0, 1),
('Test3', 1, 0),
('Test4', 1, 1);
WITH XMLNAMESPACES ('http://www.w3.org/2001/XMLSchema-instance' AS i)
SELECT TOP 1 'Setting1' AS [Setting/Name],
CASE Setting1 WHEN 1 THEN 'true' ELSE 'false' END AS [Setting/Value]
FROM #TestTable
WHERE Setting1 = 1
FOR XML PATH('Settings')
Try changing:
AS [Setting/Value]
To be:
AS 'i:value'
e.g.
WITH XMLNAMESPACES ('http://www.w3.org/2001/XMLSchema-instance' AS i)
SELECT TOP 1 'Setting1' AS 'i:name',
CASE Setting1 WHEN 1 THEN 'true' ELSE 'false' END AS 'i:value'
FROM MyTable
FOR XML PATH('Settings')
I finally gave up trying to find a way to do this with a SQL Query, though if anyone does figure this out I am still interested to know the answer.
What I ended up doing was to write a C# Windows Forms application (because I like to launch the code I want with a button as opposed to a more common console application).
The code for this is as follows if anyone is interested.
This is the AdditionalSettings class.
[System.Runtime.Serialization.CollectionDataContract(Namespace = "", Name = "Settings", ItemName = "Setting", KeyName = "Name", ValueName = "Value")]
public class AdditionalSettings : Dictionary<string, object>
{
}
The code is below:
using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Text;
using System.Windows.Forms;
namespace PopulateSettings
{
public partial class frmMain : Form
{
public frmMain()
{
InitializeComponent();
}
private void btnDoThis_Click(object sender, EventArgs e)
{
DataTable sources = GetSettings();
foreach (DataRow dr in sources.Rows)
{
AdditionalSettings settings = new AdditionalSettings();
int settingID = (int)dr["SettingID"];
bool setting1 = dr["Setting1"] == DBNull.Value ? false : (bool)dr["Setting1"];
bool setting2 = dr["Setting2"] == DBNull.Value ? false : (bool)dr["Setting2"];
bool setting3 = (int)dr["Setting3"] == 0 ? false : true;
bool setting4 = dr["Setting4"] == DBNull.Value ? false : (bool)dr["Setting4"];
AddToDictionary(settings, "Setting1", setting1);
AddToDictionary(settings, "Setting2", setting2);
AddToDictionary(settings, "Setting3", setting3);
AddToDictionary(settings, "Setting4", setting4);
string additionalSettings = Serialize<AdditionalSettings>(settings);
UpdateSources(settingID, additionalSettings);
}
}
private DataTable GetSettings()
{
DataTable settings = null;
string sqlString = #"SELECT SettingID, Setting1, Setting2, Setting3, Setting4
FROM dbo.Settings
WHERE Setting1 = 1
OR Setting2 = 1
OR Setting3 = 1
OR Setting4 = 1";
using (var cnMy = new SqlConnection(ConfigurationManager.AppSettings["MyConnectionString"]))
{
using (var cmd = new SqlCommand(sqlString, cnMy))
{
cmd.CommandType = CommandType.Text;
cnMy.Open();
using (var da = new SqlDataAdapter(cmd))
{
settings = new DataTable();
da.Fill(settings);
}
}
}
return settings;
}
private void AddToDictionary(AdditionalSettings dictionary, string name, bool setting)
{
if (setting)
{
dictionary.Add(name, setting);
}
}
public string Serialize<T>(T Data)
{
string strXML = System.String.Empty;
System.Xml.XmlWriterSettings xmlWriterSettings = new System.Xml.XmlWriterSettings();
xmlWriterSettings.OmitXmlDeclaration = true;
xmlWriterSettings.NamespaceHandling = System.Xml.NamespaceHandling.OmitDuplicates;
xmlWriterSettings.Indent = true;
var serializer = new System.Runtime.Serialization.DataContractSerializer(typeof(T));
System.Text.StringBuilder sbXML = new StringBuilder();
using (System.IO.StringWriter oStringWriter = new System.IO.StringWriter(sbXML))
{
using (System.Xml.XmlWriter xmlWriter = System.Xml.XmlWriter.Create(oStringWriter, xmlWriterSettings))
{
serializer.WriteObject(xmlWriter, Data);
xmlWriter.Flush();
}
strXML = sbXML.ToString();
}
return strXML;
}
private void UpdateSources(int settingID, string additionalSettings)
{
string sqlString = #"UPDATE dbo.Settings SET AdditionalSettings = #AdditionalSettings WHERE SettingID = #SettingID";
using (var cnMy = new SqlConnection(ConfigurationManager.AppSettings["MyConnectionString"]))
{
using (var cmd = new SqlCommand(sqlString, cnMy))
{
cmd.CommandType = CommandType.Text;
cmd.Parameters.Clear();
cmd.Parameters.Add("#AdditionalSettings", SqlDbType.VarChar).Value = additionalSettings;
cmd.Parameters.Add("#SettingID", SqlDbType.Int).Value = settingID;
cnMy.Open();
cmd.ExecuteNonQuery();
}
}
}
}
}

Update SQL table very slow

I have problem when I try to update SQL table with
I have datagridview and I need to update SQL table and take the value form my datagridview . my datagridview have more than 10000 rows
I take time more than 1:30 hour very slow
datagridview name "dgv_balance"
Here is the code:
using (SqlConnection cn = new SqlConnection())
{
cn.ConnectionString = "My Connection"
cn.Open();
using (SqlCommand cmd_select = new SqlCommand())
{
for (int i = 0; i < dgv_balance.RowCount; i++)
{
cmd_select.Connection = cn;
cmd_select.CommandType = CommandType.StoredProcedure;
cmd_select.CommandText = "clients_balances_select_glid_date";
cmd_select.Parameters.AddWithValue("#glid", Convert.ToString(dgv_balance.Rows[i].Cells[0].Value));
cmd_select.Parameters.AddWithValue("#date", Convert.ToDateTime(dgv_balance.Rows[i].Cells[2].Value));
if (cmd_select.ExecuteScalar().ToString()=="")
{
using (SqlCommand cmd_insert = new SqlCommand())
{
cmd_insert.Connection = cn;
cmd_insert.CommandType = CommandType.StoredProcedure;
cmd_insert.CommandText = "clients_balances_insert_data";
cmd_insert.Parameters.AddWithValue("#glid", Convert.ToString(dgv_balance.Rows[i].Cells[0].Value));
cmd_insert.Parameters.AddWithValue("#name", Convert.ToString(dgv_balance.Rows[i].Cells[1].Value));
cmd_insert.Parameters.AddWithValue("#date", Convert.ToString(dgv_balance.Rows[i].Cells[2].Value));
cmd_insert.Parameters.AddWithValue("#balance", Convert.ToString(dgv_balance.Rows[i].Cells[3].Value));
cmd_insert.ExecuteNonQuery();
cmd_insert.Parameters.Clear();
}
}
else
{
using (SqlCommand cmd_update= new SqlCommand())
{
cmd_update.Connection = cn;
cmd_update.CommandType = CommandType.StoredProcedure;
cmd_update.CommandText = "clients_balances_update_balance";
cmd_update.Parameters.AddWithValue("#glid", Convert.ToString(dgv_balance.Rows[i].Cells[0].Value));
cmd_update.Parameters.AddWithValue("#date", Convert.ToString(dgv_balance.Rows[i].Cells[2].Value));
cmd_update.Parameters.AddWithValue("#balance", Convert.ToString(dgv_balance.Rows[i].Cells[3].Value));
cmd_update.ExecuteNonQuery();
cmd_update.Parameters.Clear();
}
}
cmd_select.Parameters.Clear();
}
}
}
You may have to call SELECT command for one time only before you loop through your datagridview rows and cache the result data and check on the result while iterating your datagridview instead of calling it on each row. This way you will reduce your commands by 10000.
It also better if you could show us your procedures' queries.
Or if your datagridview is the ONLY source for your data then you can delete all your previous data in your database and make one insert call for all of your datagridview data.
Try this:
using (SqlConnection cn = new SqlConnection())
{
cn.ConnectionString = "MyConnection" ;
cn.Open();
SqlDataAdapter da = new SqlDataAdapter();
DataTable dt = new DataTable();
using (SqlCommand cmd_select = new SqlCommand())
{
cmd_select.Connection = cn; cmd_select.CommandType = CommandType.StoredProcedure; cmd_select.CommandText = "clients_balances_select_glid_date";
da.SelectCommand = cmd_select;
da.Fill(dt);
for (int i = 0; i < dgv_balance.RowCount; i++)
{
if(/* check here if dt contains this row*/)
{
// Insert
}
else
{
// Update
}
}
}
}
I think you should insert or update all data one time.
Create index for glId column. If glId is primary key, it's indexed.
Assumes that List ClientBalance is list items you need update or insert.
public class ClientBalance
{
GlId int {get;set;}
ClientName string {get;set;}
Balance decimal {get;set;}
DateInput DateTime {get;set;}
}
You could serialize list Item to xml string and pass it to store procedure
public string Serialize<T>(T value) where T : new()
{
var serializeXml = string.Empty;
if (value != null)
{
try
{
var xmlserializer = new XmlSerializer(typeof(T));
var stringWriter = new StringWriter();
var writer = XmlWriter.Create(stringWriter);
xmlserializer.Serialize(writer, value);
serializeXml = stringWriter.ToString();
writer.Close();
}
catch (Exception ex)
{
return string.Empty;
}
}
return serializeXml;
}
Create a new store procedure for insert or update item like that:
CREATE PROCEDURE [dbo].[clients_balances_insert_or_update]
(
#xmlObject nvarchar(max)
)
AS
BEGIN
-- TABLE INCLUDE DATE FROM XML
DECLARE #tblBalances AS TABLE
(
GlId int,
DateInput datetime,
ClientName nvarchar(50),
Balance decimal(18,2)
)
DECLARE #idoc int -- xml id
-- PARSE XML TO OBJECT
EXEC sp_xml_preparedocument #idoc OUTPUT, #xmlObject
INSERT INTO #tblBalances
(
GlId, DateInput, ClientName, Balance
)
SELECT s.GlId, s.DateInput, s.ClientName, s.Balance
FROM OPENXML (#idoc, '/ArrayOfClientBalance/ClientBalance', 8) WITH (
GlId int 'GlId',
DateInput datetime 'DateInput',
ClientName NVARCHAR(50) 'ClientName',
Balance DECIMAL(18,2) 'Balance'
) s
EXEC sp_xml_removedocument #idoc
-- USE MERGE FOR INSERT OR UPDATE DATE
-- Use transaction
BEGIN TRAN InsertOrUpdate
BEGIN TRY
MERGE Target AS T
USING #tblBalances AS S
ON (T.GlId = S.GlId)
WHEN NOT MATCHED BY TARGET
THEN INSERT( GlId, DateInput, ClientName, Balance) VALUES( GlId, DateInput, ClientName, Balance)
WHEN MATCHED
THEN UPDATE SET DateInput = S.DateInput, Balance = s.Balance
COMMIT TRAN InsertOrUpdate;
END TRY
BEGIN CATCH
ROLLBACK TRAN InsertOrUpdate;
THROW;
END CATCH
END
Hope this helpfully!

How to insert another table data from select query for exist table

Actually I'm creating one database application where if person first day login then his sales_count will be 1, same person login again then its sales_count will be 2 , same user login next day then its sales_count again 1.
For this I created two tables Login and Sales_Details. In Login I have:
User_name, Password and Unique no.
Now, in sales_details I want to fetch only User_name,Unique_no from login detail but at same time I want to increment sales_count in sales_details table also update today date.
Sales_details has
Sales_id,User_name,Unique_No,Sales_count,To_Date field
Actually I tried but nothing happen if To_date is null then insert today date+sales_count as 1 in sales_details
Below I'm pasting my whole code:
string todaydate = DateTime.Now.ToString("dd/MM/yyyy");
string access = "select To_Date from Sales_Details";
cmd = new OleDbCommand(access, con);
con.Open();
using (OleDbDataReader read = cmd.ExecuteReader()){
while (read.Read()){
string date2 = read["To_Date"].ToString();
if (todaydate == date2){
cmd = new OleDbCommand("update Sales_Details set Sales_count= IIF(IsNull(Sales_count), 0, Sales_count) + 1, [To_Date]=Date() where [Unique_No]=#Unique_No", con);
cmd.Parameters.AddWithValue("#Unique_No", txtinput.Text);
con.Open();
int n = cmd.ExecuteNonQuery();
if (n == 0) {
MessageBox.Show("Invalid Unique No.");
} else {
this.DialogResult = DialogResult.OK;
}
con.Close();
} else {
int counter=1;
cmd = new OleDbCommand("insert into Sales_Details select User_name,Unique_No from Login where Unique_No=#Unique_No Union select ISNULL(Sales_Count+1,0) as [#Sales_Count],DATE() AS [To_date]", con);
cmd.Parameters.AddWithValue("#Unique_No", txtinput.Text);
cmd.Parameters.AddWithValue("#Sales_count",counter);
int n1 = cmd.ExecuteNonQuery();
if (n1 == 0){
MessageBox.Show("Invalid Unique No.");
} else {
this.DialogResult = DialogResult.OK;
}
}
}
}
con.Close();

Changing datetime to date data type?

ALTER PROCEDURE [Deal].[USP_LoadDealHistoryByDealId]
(#DealId int,
#chk int)
AS
IF (#chk = 1)
BEGIN
SELECT
DDT.FieldType AS field,
DDT.OldValue as old,
DDT.NewValue as new,
AU.FullName AS Name,
DDT.UpdateOn AS UpdatedOn
FROM
[Deal].[DealTransaction] as DDT
INNER JOIN
AD.Users as AU ON AU.UserId = DDT.[UpdateBy]
WHERE
DDT.dealId = #DealId
END
ELSE if(#chk = 2)
BEGIN
SELECT
'No Data' as field ,
0 as old ,
0 as new ,
AU.FullName AS Name,
DD.UpdatedOn AS UpdatedOn
FROM
AD.Users as AU
INNER JOIN
[Deal].[Deals] AS DD ON AU.UserId = DD.UploadedBy
WHERE
DD.dealId = #DealId
END
UpdatedOn column is of datatype datetime and it shows to my HTML table like 10-09-1992/12.00.... But I want to show just date like 10-09-1992, what should I do?
Here Is my HTML table
public string LoadDealHistory(DealHistory aDealhistory)
{
StringBuilder html = new StringBuilder();
try {
using (DealTranctionGateway dealTranctionGateway = new DealTranctionGateway())
{
DataTable dt = new DataTable();
dt = dealTranctionGateway.LoadDealHistory(aDealhistory);
string dealHistory = "";
if (dt.Rows.Count > 0)
{
html.Append("<table class='table table-bordered'>");
html.Append("<thead>");
html.Append("<tr>");
html.Append("<th>S.No</th>");
html.Append("<th>FieldType</th>");
html.Append("<th>OldValue</th>");
html.Append("<th>NewValue</th>");
html.Append("<th>Full Name</th>");
html.Append("<th>UpdateOn</th>");
html.Append("</thead>");
html.Append("</tr>");
for (int i = 0; i < dt.Rows.Count; i = i + 1)
{
int sNo = i + 1;
html.Append("<tr>");
html.Append("<td>" + sNo + "</td>");
html.Append("<td>" + dt.Rows[i]["field"] + "</td>");
html.Append("<td>" + dt.Rows[i]["old"] + "</td>");
html.Append("<td>" + dt.Rows[i]["new"] + "</td>");
html.Append("<td>" + dt.Rows[i]["Name"] + "</td>");
html.Append("<td>" + dt.Rows[i]["UpdatedOn"] + "</td>");
html.Append("</tr>");
}
html.Append("</tbody>");
html.Append("</table>");
}
}
}
catch (Exception ex)
{
}
return html.ToString();
}
}
Updated:
Tried this:
string updateOn = "";
updateOn = ((DateTime)dt.Rows[i]["UpdatedOn"]).ToString("dd-MM-yyyy", CultureInfo.InvariantCulture);
html.Append("<td>" + updateOn + "</td>");
OR
You can use format DateTime in SQL:
More format at here.
In your case, it should be using style 105.
SELECT replace(convert(NVARCHAR, UpdatedOn, 105), ' ', '-')
You can convert it to string like:
dt.Rows[i]["UpdatedOn"].ToString("dd-MM-yyyy")
No need for any changes on SQL Server side, date formatting is a front-end problem.
Select convert(date,getdate())