How to insert a Null Value to a column if there is no data provided from source file in ASP.NET - sql

I am inserting data from a Text file to table.
and the SPROC is as follows
ALTER PROCEDURE [dbo].[SPROC]
-- Add the parameters for the stored procedure here
#DBName VARCHAR(30),
#FirstLine VARCHAR(MAX)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #InsertQuery NVARCHAR(MAX), #Summary_ID INT
SET #InsertQuery = 'INSERT INTO ' + #DBName + '.[dbo].[Summary] VALUES ( ' + #FirstLine + '); SELECT SCOPE_IDENTITY()'
EXEC SP_EXECUTESQL #InsertQuery
END
Now the thing is, if it has 8 values it will get inserted. If 8 th Value is not there in the text file it is throwing Error column name or number of supplied values does not match table definition
How can i handle this error and If there is no value for 8th column it should insert the value as NULL.
Reading File code:
public static String[] ReadSummary_Into_Array(string filepath)
{
StreamReader sreader = null;
int counter = 0;
try
{
sreader = new StreamReader(filepath);
string line = sreader.ReadLine();
//condition to hanlde empty file
if (line == null) return null;
//condition to hanlde empty first line file
if (line == "") return new String[0];
FirstLine = line;
string cleaned_line = line.Replace("''", "'-'").Replace("','", "''");
string word = "";
List<string> data = new List<string>();
MatchCollection matches = Regex.Matches(cleaned_line, #"'([^']*)");
//String[] words = null;
foreach (Match match in matches)
{
word = match.ToString();
string word_edited = word.Replace("\'", "");
if (word_edited != string.Empty)
{
data.Add(word_edited);
counter++;
}
}
Summary = new String[counter];
Summary = data.ToArray(); //The Summary Line is reconstructed into a String array
return Summary;
}

If you dont have value then you must specify the column names.
Try like this
ALTER PROCEDURE [dbo].[SPROC]
-- Add the parameters for the stored procedure here
#DBName VARCHAR(30),
#FirstLine VARCHAR(MAX)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #InsertQuery NVARCHAR(MAX), #Summary_ID INT, #CountS INT
SET #CountS = len(#FirstLine) - len(replace(#FirstLine, ',', ''))
IF #CountS >= 7 THEN
SET #InsertQuery = 'INSERT INTO ' + #DBName + '.[dbo].[Summary] VALUES ( ' + #FirstLine + '); SELECT SCOPE_IDENTITY()'
ELSE
SET #InsertQuery = 'INSERT INTO ' + #DBName + '.[dbo].[Summary](SerialNumber,AssetNumber,SoftwareRev,TechName,StartTime,StopTime,Status) VALUES ( ' + #FirstLine + '); SELECT SCOPE_IDENTITY()'
END IF
EXEC SP_EXECUTESQL #InsertQuery
END

Similar as Vignesh, but in your C# code
if ( Regex.Matches( strLine, "," ).Count == 7)
{
strLine = strLine + ', null';
}

Related

What's the limit of a variable in T-SQL? Why does my variable prints out as NULL?

I'm creating a stored procedure with the following code:
CREATE OR ALTER PROCEDURE Insert_Into_Table
#Origin VARCHAR(255),
#Destination VARCHAR(255),
#Origin_Columns VARCHAR (4000),
#Destination_Columns VARCHAR (4000),
#Delete_Date_Column_Name VARCHAR(63), --Nullable
#Delete_Period_Months INT -- Nullable
AS
BEGIN TRY
DECLARE #insert_query VARCHAR(4000) = NULL;
DECLARE #delete_query VARCHAR(4000) = NULL;
DECLARE #check_query VARCHAR (4000) = NULL;
DECLARE #Date_To_Delete DATETIME = CAST(DATEADD(MONTH, -#Delete_Period_Months, GETDATE()) AS DATETIME);
-- Table names cannot be referenced directly in SPs, so we bypass
-- this issue by declaring a variable containing the query
IF #Delete_Date_Column_Name IS NOT NULL
OR #Delete_Period_Months IS NOT NULL
SET #delete_query = 'DELETE FROM ' + #Destination + ' WHERE ' +
#Delete_Date_Column_Name + ' >= ' + CONCAT(CHAR(39),CAST(#Date_To_Delete AS VARCHAR(255)),CHAR(39));
ELSE
PRINT N'Missing or no values provided for table deletion. Only executing copy';
CREATE TABLE #temptable (count INT)
SET #check_query = 'INSERT INTO #temptable SELECT TOP 1 1 AS count FROM ' + #Origin
EXECUTE(#check_query)
SET #insert_query = 'INSERT INTO' + QUOTENAME(#Destination) + QUOTENAME(#Destination_Columns, '()') +
'SELECT ' + #Origin_Columns + ' FROM ' + QUOTENAME(#Origin);
BEGIN TRY
IF EXISTS (SELECT TOP 1 * FROM #temptable)
BEGIN TRANSACTION
EXECUTE(#delete_query);
EXECUTE(#insert_query);
COMMIT
END TRY
BEGIN CATCH
ROLLBACK;
THROW 51000, 'The Origin table is empty', 1;
END CATCH
END TRY
BEGIN CATCH
THROW 51000, 'Error creating transaction', 1;
END CATCH
GO
When executing the stored proecedure with the parameters shown, it works correctly:
EXEC Insert_Into_Table
#Origin = 'Sink_Proc',
#Destination = 'Sink_Test',
#Origin_Columns = 'customer, order_number, created_date',
#Destination_Columns = 'customer, order_number, created_date',
#Delete_Date_Column_Name = NULL,
#Delete_Period_Months = NULL
However, when executing it with 25+ columns as Origin/Destination columns, when I print the #insert_query variable, it returns NULL and no operation is done. Why is this happening?

SQL smart search possible?

I am trying to pull a list from a large repository. And if there are spaces in this search, I separate the spaces and search separately. So far everything is working fine. And I am sending a list to the JS side to highlight the searched words. The word in the example search is 'paston'. I need to search for it as 'piston' or 'peston', is it possible? The only way I could think of was to change each letter of the words coming from the search in SQL to _ respectively and add them to the end with or, like '_iston' or 'p_ston' or 'pi_ton'. but I'm not sure if this works slow. Does anyone have any suggestions or know of a ready-made structure in SQL?
My SQL code is like this:
ALTER PROCEDURE [dbo].[GetStoklar]
#PageIndex nvarchar(15)
,#PageSize nvarchar(15)
,#Ara nvarchar(max)
AS
BEGIN
DECLARE #sql NVARCHAR(MAX);
DECLARE #NAME VARCHAR(100);
SET #sql = '
Select STOK_KODU,STOK_ADI,GRUP_KODU from TBLSTSABIT where 1=1'
DECLARE CUR CURSOR FOR
SELECT Deger FROM dbo.splitstring(''+#Ara+'')
OPEN CUR
FETCH NEXT FROM CUR INTO #NAME
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sql=#sql+' AND STOK_ADI+STOK_KODU+GRUP_KODU LIKE ''%'+#NAME+'%'''
FETCH NEXT FROM CUR INTO #NAME
END
CLOSE CUR
DEALLOCATE CUR
SET #sql = #sql + ' order by STOK_KODU asc offset (CAST('+#PageIndex+' as int)*CAST('+#PageSize+' as int)) Rows fetch next CAST('+#PageSize+' as int) rows only
'
EXEC sp_executesql #sql;
PRINT #SQL;
RETURN
END
on the C# side like this
StringBuilder test = new StringBuilder();
JsonModel jsonmodel = new JsonModel();
if (Arama != "")
{
foreach (var item in Arama.Split(' '))
{
test.Append(item + "~");
}
}
test.Remove(test.ToString().Length - 1, 1);
jsonmodel.Filtre = test.ToString();
int pagesize = 15;
var tbrow = isStatic.GetStokListesi(pageindex, pagesize, Arama);
jsonmodel.NoMoredata = tbrow.Count < pagesize;
jsonmodel.HTMLString = isStatic.RenderToString(PartialView("_partial", tbrow));
return Json(jsonmodel);
This is the search function.
public static List<Stoklar> GetStokListesi(int pageindex, int pagesize, string Arama)
{
using (blabla db = new blabla())
{
return db.Database.SqlQuery<Stoklar>("[GetStoklar] #PageIndex,#PageSize,#Ara",
new SqlParameter("#PageIndex", pageindex.ToString()), new SqlParameter("#PageSize", pagesize.ToString()), new SqlParameter("#Ara", Arama)).ToList();
}
}
Is there a way to use this more meaningfully on the SQL side?
You can replace all single characters in a word by an '_', and then use these results in a LIKE
For replacing all single characters in a word, see: DBFIDDLE

How to compare two strings based on percent match in SQL

I want to post a solution to a interesting problem I was facing in T-SQL.
The problem:
Compare two string fields based on a percent match.
In addition, the two strings may have the words in them translocated.
For example: "Joni Bravo" and "Bravo Joni". These two strings should return a match of 100%, which means that position is not relevant. Few more things worth noting are that this code is made to compare strings that have space as delimiter in them. If the first string doesnt have space the match is set to 100% without actual check. This was not developed, because the strings this function is ment to compare always contain two or more words. Also, it is written on MS SQL Server 2017 if that mathers.
So here is the solution, hope this helps anyone :)
gl
/****** Object: UserDefinedFunction [dbo].[STRCOMP] Script Date: 29/03/2018 15:31:45 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[STRCOMP] (
-- Add the parameters for the function here
#name_1 varchar(255),#name_2 varchar(255)
)
RETURNS float
AS
BEGIN
-- Declare the return variable and any needed variable here
declare #p int = 0;
declare #c int = 0;
declare #br int = 0;
declare #p_temp int = 0;
declare #emergency_stop int = 0;
declare #fixer int = 0;
declare #table1_temp table (
row_id int identity(1,1),
str1 varchar (255));
declare #table2_temp table (
row_Id int identity(1,1),
str2 varchar (255));
declare #n int = 1;
declare #count int = 1;
declare #result int = 0;
declare #total_result float = 0;
declare #result_temp int = 0;
declare #variable float = 0.0;
--clean the two strings from unwanted symbols and numbers
set #name_1 = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(#name_1,'!',''),' ',' '),'1',''),'2',''),'3',''),'4',''),'5',''),'0',''),'6',''),'7',''),'8',''),'9','');
set #name_2 = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(#name_2,'!',''),' ',' '),'1',''),'2',''),'3',''),'4',''),'5',''),'0',''),'6',''),'7',''),'8',''),'9','');
--check if the first string has more than one words inside. If the string does
--not have more than one words, return 100%
set #c = charindex(' ',substring(#name_1,#p,len(#name_1)));
IF(#c = 0)
BEGIN
RETURN 100.00
END;
--main logic of the operation. This is based on sound indexing and comparing the
--outcome. This loops through the string whole words and determines their soundex
--code and then compares it one against the other to produce a definitive number --showing the raw match between the two strings #name_1 and #name_2.
WHILE (#br != 2 or #emergency_stop = 20)
BEGIN
insert into #table1_temp(str1)
select substring (#name_1,#p,#c);
set #p = len(substring (#name_1,#p,#c))+2;
set #p = #p + #p_temp - #fixer;
set #p_temp = #p;
set #c = CASE WHEN charindex(' ',substring(#name_1,#p,len(#name_1))) = 0 THEN len(#name_1) ELSE charindex(' ',substring(#name_1,#p,len(#name_1))) END;
set #fixer = 1;
set #br = CASE WHEN charindex(' ',substring(#name_1,#p,len(#name_1))) = 0 THEN #br + 1 ELSE 0 END;
set #emergency_stop = #emergency_stop +1;
END;
set #p = 0;
set #br = 0;
set #emergency_stop = 0;
set #fixer = 0;
set #p_temp = 0;
set #c = charindex(' ',substring(#name_2,#p,len(#name_2)));
WHILE (#br != 2 or #emergency_stop = 20)
BEGIN
insert into #table2_temp(str2)
select substring (#name_2,#p,#c);
set #p = len(substring (#name_2,#p,#c))+2;
set #p = #p + #p_temp - #fixer;
set #p_temp = #p;
set #c = CASE WHEN charindex(' ',substring(#name_2,#p,len(#name_2))) = 0 THEN len(#name_2) ELSE charindex(' ',substring(#name_2,#p,len(#name_2))) END;
set #fixer = 1;
set #br = CASE WHEN charindex(' ',substring(#name_2,#p,len(#name_2))) = 0 THEN #br + 1 ELSE 0 END;
set #emergency_stop = #emergency_stop +1;
END;
WHILE((select str1 from #table1_temp where row_id = #n) is not null)
BEGIN
set #count = 1;
set #result = 0;
WHILE((select str2 from #table2_temp where row_id = #count) is not null)
BEGIN
set #result_temp = DIFFERENCE((select str1 from #table1_temp where row_id = #n),(select str2 from #table2_temp where row_id = #count));
IF(#result_temp > #result)
BEGIN
set #result = #result_temp;
END;
set #count = #count + 1;
END;
set #total_result = #total_result + #result;
set #n = #n + 1;
END;
--gather the results and transform them in a percent match.
set #variable = (select #total_result / (select max(row_count) from (
select max(row_id) as row_count from #table1_temp
union
select max(row_id) as row_count from #table2_temp) a));
RETURN #variable/4 * 100;
END
GO
PS: I decided to write it in a user-defined function just for the needs of my project.

Export database table to existing excel file

I've looked already but what I found so far is exporting to a existing excel sheet, what I need is to make a copy of an existing excel template I have and pass my data there. I just need to be pointed in the right way, hope I'm clear enough.
EDIT
I have an application working on Java to which I will add this.
Assuming that you ask about SQL Server, you can create 2 step job, one for copying your xls, and in second step using openrowset/insert into your copied excel file.
Here is Tsql which copies template and also sends an email, and info about xp_cmdshell https://msdn.microsoft.com/en-us/library/ms190693.aspx
DECLARE #cmd varchar(512)
DECLARE #fd varchar(512)
DECLARE #odbc varchar(128)
DECLARE #db varchar(128)
SELECT #fd = 'D:\Reports\Exact\ByWeek' + CONVERT(VARCHAR(10), GETDATE()-8,120)+'_'+CONVERT(VARCHAR(10), GETDATE(),120)+'.xls'
SELECT #cmd = 'copy D:\Reports\System\shipments_week.xls ' + #fd
EXEC MASTER..XP_CMDSHELL #cmd, NO_OUTPUT
SET #odbc = 'Microsoft.Jet.OLEDB.4.0'
SET #db = 'Excel 8.0;Database=' + #fd
exec('INSERT INTO OPENrowset(''' + #odbc + ''',''' + #db + ''',''SELECT
OrderNr,Debtor,SUM_NSHIPPED,SUM_TOTAL,PERC_NSHIPPED,ORDDAT,INVDAT,ORD_SYSCREATED,HIST_LAST_MODIFIED,PT_WZ_SENT
FROM [Shipped$]'')
SELECT * FROM salag_shipmentsbyWeek')
exec('INSERT INTO OPENrowset(''' + #odbc + ''',''' + #db + ''',''SELECT
OrderNr,Debtor,SUM_NSHIPPED,SUM_TOTAL,PERC_NSHIPPED,ORDDAT,INVDAT,ORD_SYSCREATED,HIST_LAST_MODIFIED,PT_WZ_SENT
FROM [SB$]'')
SELECT * FROM salag_shipmentsbyWeek WHERE Debtor NOT LIKE ''%CASTORAMA%'' AND Debtor NOT LIKE ''Praktiker%''')
DECLARE #Body VARCHAR(4096)
DECLARE #BodyType VARCHAR(16)
DECLARE #path VARCHAR(128)
DECLARE #f VARCHAR(32)
DECLARE #topic VARCHAR(128)
SELECT #f = CONVERT(VARCHAR(10), GETDATE()-8,120)+'_'+CONVERT(VARCHAR(10), GETDATE(),120)
SELECT #topic = 'New Report ['+ CONVERT(VARCHAR(10), GETDATE()-8,120)+'_'+CONVERT(VARCHAR(10), GETDATE(),120) + ']'
SELECT #path = '\\appsrv\Reports\Exact\ByWeek' + CONVERT(VARCHAR(10), GETDATE()-8,120)+'_'+CONVERT(VARCHAR(10), GETDATE(),120)+'.xls'
SELECT #Body = 'New Scan Report has been created: '+#f+' '+ #path
SELECT #BodyType = 'HTMLBody'
exec sp_send_cdosysmail 'Reports Info ','reports#foo ar.com',#topic, #Body, #BodyType
I was able to achieve what I was looking for using JExcel and it was pretty easy, here I will share my code and hope it helps someone in the future. Sorry its not properly commented yet, I will later post an update.
Db_Connect connection = new Db_Connect();
conn = connection.connect();
String originalFile = "C:\\Users\\Geni\\Desktop\\Book1-Template-new.xls";
date = date.replace("/", "-");
SimpleDateFormat myDate = new SimpleDateFormat("yyyy-MM-dd");
try{
Workbook original = Workbook.getWorkbook(new File(originalFile));
WritableWorkbook copy = Workbook.createWorkbook(new File(date+".xls"), original);
java.util.Date format = myDate.parse(date);
java.sql.Date newDate = new java.sql.Date(format.getTime());
String sql = "SELECT Name, sporecount.* FROM sporesfungi "
+ "INNER JOIN sporecount ON sporesfungi.IDSpore = sporecount.IDSpore"
+ "WHERE Date = ? ORDER BY TraceNum";
PreparedStatement statement = conn.prepareStatement(sql);
statement.setDate(1, newDate);
rs = statement.executeQuery();
/*stmt = conn.createStatement();
rs = stmt.executeQuery(sql);*/
WritableSheet sheet = copy.getSheet(0);
WritableCell cell;
String spore;
while(rs.next()){
for(int i = 2; i < 64 ;i++){
cell = sheet.getWritableCell(1,i);
spore = cell.getContents();
if(rs.getString("Name").equals(spore)){
Number l1 = new Number(14-rs.getInt("TraceNum"),i,rs.getInt("Amount")) ;
sheet.addCell(l1);
}
}
}
copy.write();
copy.close();
original.close();
}
catch (BiffException | IOException e) {
}

Parametrize query in t-sql

SELECT TOP #columnCount #columnName
FROM #tableName
I get the following error
Incorrect syntax near '#columnCount'.
What could be wrong?
If I change to
SELECT TOP (#columnCount) #columnName
FROM #tableName
I get the following error
Must declare the table variable "#tableName".
I run it from C#
A safe and secure way would be
DECLARE #columnCount INT = 100
DECLARE #columnName NVARCHAR(128) = 'YourColumnName'
DECLARE #tableName NVARCHAR(128) = 'YourTableName'
DECLARE #Sql NVARCHAR(MAX);
SET #Sql = N'SELECT TOP (#columnCount) ' + QUOTENAME(#columnName) + N'
FROM ' + QUOTENAME(#tableName)
EXECUTE sp_executesql #Sql
,N'#columnCount INT'
,#columnCount
You need dynamic SQL to accomplish what you're trying to do.
DECLARE #sql VARCHAR(max);
SET #sql = 'SELECT TOP ' + #columnCount + ' ' + #columnName + ' FROM ' + #tableName;
EXEC(#sql);
The variables used need to be converted appropriately.
Read more in the documentation
Column lists and Table names cannot be parameters. However, since you are running this from C# you are technically already using Dynamic SQL (unless you are calling a stored procedure with those params but there is no mention here of stored procedures being used so for now I will assume not). When building the SQL in C#, you need to concatenate the Column List and Table Name into the query but you can still use a parameter for the value used by the TOP() operator:
SqlConnection _Connection = new SqlConnection("connection string");
SqlCommand _Command = new SqlCommand();
SqlDataReader _Reader = null;
string _Query;
string _TableName = "dbo.MyTable";
string _ColumnList = "Field1, Field2 AS [AliasedName], Field3";
int _NumberOfRows = 12;
_Query = String.Concat("SELECT TOP (#NumberOfRows) ",
_ColumnList, " FROM ", _TableName);
SqlParameter _NumRows = new SqlParameter("#NumberOfRows", SqlDbType.Int);
_NumRows.Value = _NumberOfRows;
try
{
_Connection.Open();
_Reader = _Command.ExecuteReader();
// do stuff
}
finally
{
_Reader.Close();
_Connection.Close();
}
Of course, you could also just concatenate the #NumberOfRows value directly into the query as well, but keeping it as a parameter will allow for Query Plan re-use if running this query multiple times with the same values for ColumnList and TableName but changing the #NumberOfRows value.