For loop for array which should have If condtion c# - c#

I have to iterate a array with for loop to find it contains specific words in it and add that in listbox
String[] result= ["vicky","vinay#","google#","hello"]
For (l=0 ; l<= result.length; l++)
{
If(result[l].contains("#")
{
Listbox.items.add(result[l]);
}
}
What this does is it gets only first found value I am not getting second value?

You need an ordering column for your data. Let me assume that you have one.
First add the new column:
alter table t add column id int;
Note: id is a really bad name for a column that can be null. Then:
with toupdate as (
select t.*,
row_number() over (partition by col1 order by <ordering col>) as seqnum
from t
)
update toupdate
set id = (case when col1 = 1 then seqnum end);
Strictly speaking, you don't need to update the values when col1 = 0, because the default value is NULL. However, in case you want a different value there, I am leaving out the where col1 = 1.

You can simulate a partial identity column, but you won't be able to incorporate an actual IDENTITY column to the table that works conditionally.
If you just need to update a new column with an incremental value, you can just use a ROW_NUMBER() over a filtered SELECT:
;WITH CTE AS
(
SELECT
T.Col1,
T.ID,
GeneratedID = ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) -- Determine your order here
FROM
YourTable AS T
WHERE
T.Col1 IS NOT NULL
)
UPDATE C SET
ID = C.GeneratedID
FROM
CTE AS C

Your query should be like below :
update <table_name> set id=1 where Col1=1;
update <table_name> set id=null where Col1=0;

Related

How can I sort counted DataTable rows according to specific parameter

I am trying to use dataTable.Rows.Count, but sort the result based on a specific parameter.
That parameter being "Column1" in my DataTable. So that the output gives me the rows pertaining to that distinct value only.
My DataTable is in a View, but I need to use the sorted int values in a ViewModel.
I am able to count the rows with public static int o { get; set; } and a
dt.Rows.Count in my DataTable. I then grab the value by instantiating my View in my ViewModel, with int numberOfRows = ViewName.o;.
But that gives me the total number of rows, whereas I need the number of rows per distinct value in "Column1".
My question is, where and how can I do the required sorting?
Because when I've gone as far as to count them and add them to an int (in my ViewModel), there's no way to know what row they used to represent, right?
And If I try to sort in the DataTable (in the View) somehow, I don't know how to reference the distinct values.
They might vary from time to time as the program is used, so I can't hard-code it.
Comment suggested using query instead, adding my stored procedure for help to implement solution:
SET NOCOUNT ON
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[myProcedure]
#param myUserDefinedTableType readonly
AS
BEGIN TRANSACTION
INSERT INTO [dbo].[myTable] (/* list of columns */)
SELECT [Column1], /* this is the column I need to sort by */
-- more columns
-- the rest of the columns
/* I do aggregations to my columns here, I am adding several thousands row to 20 summarized rows, so after this line, I can no longer get ALL the rows per "Column1", but only the summarized rows. How can I count the rows BEFORE I do the aggregations? */
FROM #param
GROUP BY [Column2], [Column1]
ORDER BY [Column2], [Column1]
// Some UPDATE clauses
COMMIT TRANSACTION
I believe the wisest choice is to act in the db side.
Assuming you're using SQL Server, the query should be:
SELECT *, COUNT(*) OVER (PARTITION BY Column1) AS c
FROM Table1
ORDER BY c
This query returns the data on your table "Table1", plus the column "c" that represents the count of the value of "Column1", per each row.
Finally, it sorts rows by the column "c", as you request.
EDIT
To complete this task, I will use a Common Table Expression:
-- Code before INSERT...
;WITH CTE1 AS (
SELECT *,
COUNT(*) OVER (PARTITION BY [Column1]) AS c
FROM #param
)
INSERT INTO [dbo].[myTable] (/* list of columns - must add the column c */)
SELECT [Column1],
[Column2],
[c],
-- aggregated columns
FROM CTE1
GROUP BY [Column2], [Column1], c
-- Code after INSERT...
In the Common Table Expression "CTE1" I select all the values in #param, adding a column "c" with the count per Column1.
Note: if you have 5 rows with the same value of Column1, but two different values in Column2, in myTable you will have two rows (because of the GROUP BY [Column2], [Column1]), both with c=5.
If you want instead obtain the count grouped by Column1 and Column2, you have to declare c as follows: COUNT(*) OVER (PARTITION BY [Column1], [Column2]) AS c.
I hope I was clear, If not I'm available to explain it in a different way.
EXAMPLE
CREATE TABLE myTable (col1 VARCHAR(50), col2 INT, col3 INT, c INT)
CREATE TYPE myUserDefinedTableType AS TABLE (column1 VARCHAR(50), column2 INT, column3 INT)
DECLARE #param myUserDefinedTableType
INSERT INTO #param VALUES ('A', 1, 4), ('A', 2, 3), ('A', 2, 6), ('B', 2, 3)
;WITH CTE1 AS (
SELECT *, COUNT(*) OVER (PARTITION BY [Column1]) AS c
FROM #param
)
INSERT INTO [myTable]([col1], [col2], [col3], [c])
SELECT [column1], [column2],
-- aggregated columns
MAX([column3]),
-- count
[c]
FROM CTE1
GROUP BY [column2], [column1], c
DataView dv = dt.DefaultView;
dv.Sort = "SName ASC"; -- your column name
DataTable dtsorted = dv.ToTable();
DataTable dtsorted = dv.ToTable(true, "Sname","Surl" ); //return distinct rows

sql select a default row if the result is not found

Suppose that I have table that holds some data for individuals and companies, and I want to retrieve default value if no data found for individuals or companies, for example, suppose that I have a table
CustomerAccountId CustomerAccountType DueDays IsAdjustable isDefaultForIndividual isDefaultForCompany
1 Individual 10 true false false
2 Company 20 false false false
null null 5 false true false
null null 30 true false true
I want to create a function that takes two parameters IndividualCustomerAccountId and CompanyCustomerAccountId if IndividualCustomerAccountId found in the table retrieve it, if not found retrieve the default value for individuals which is the third row in this case , the same for companies, if theCompanyCustomerAccountIdis found retrieve it, if not get the default value for the companies which isfourth row` in this case.
suppose that we created a funtion which accepts IndividualCustomerAccountId as the first parameter and CompanyCustomerAccountId as the second parameter
sample input
MyFunc(1 , 2) should return first and second rows
MyFunc(1 , 50) should return first and fourth rows because no company with CustomerAccountId 50 found in the table so retrieve the default value for companies which is the fourth row
MyFunc(100 , 2) should return second and third rows because no individual with customer account Id 100 is found so we get the default value for individuals which is the third row, and we have a company with customerAccountId 2, so we simply can retrive it from the table.
I want to create either a LINQ query or SQL function to achieve these results
You could try SQL function
CREATE TABLE Customer
(
CustomerAccountId int,
CustomerAccountType varchar(20),
DueDays int,
IsAdjustable bit,
isDefaultForIndividual bit,
isDefaultForCompany bit
)
INSERT INTO Customer VALUES
(1, 'Individual', 10, 1,0,0),
(2, 'Company', 20, 0,0,0),
(null, null, 5, 0,1,0),
(null, null, 30, 1,0,1)
GO
CREATE FUNCTION MyFunc
(
#IndividualCustomerAccountId int,
#CompanyCustomerAccountId int
)
RETURNs #result TABLE
(
CustomerAccountId int,
CustomerAccountType varchar(20),
DueDays int,
IsAdjustable bit,
isDefaultForIndividual bit,
isDefaultForCompany bit
)
BEGIN
INSERT INTO #result
SELECT CustomerAccountId , CustomerAccountType, DueDays, IsAdjustable, isDefaultForIndividual,isDefaultForCompany
FROM Customer c
WHERE (CustomerAccountId = #IndividualCustomerAccountId AND CustomerAccountType = 'Individual')
OR (CustomerAccountId = #CompanyCustomerAccountId AND CustomerAccountType = 'Company')
IF(NOT EXISTS (SELECT 1 FROM Customer c
WHERE CustomerAccountId = #IndividualCustomerAccountId AND CustomerAccountType = 'Individual' ))
BEGIN
INSERT INTO #result
SELECT CustomerAccountId , CustomerAccountType, DueDays, IsAdjustable, isDefaultForIndividual,isDefaultForCompany
FROM Customer c
WHERE CustomerAccountId IS NULL AND isDefaultForIndividual = 1
END
IF(NOT EXISTS (SELECT 1 FROM Customer c
WHERE CustomerAccountId = #CompanyCustomerAccountId AND CustomerAccountType = 'Company' ))
BEGIN
INSERT INTO #result
SELECT CustomerAccountId , CustomerAccountType, DueDays, IsAdjustable, isDefaultForIndividual,isDefaultForCompany
FROM Customer c
WHERE CustomerAccountId IS NULL AND isDefaultForCompany = 1
END
RETURN;
END
GO
SELECT * from dbo.MyFunc(1,2)
SELECT * from dbo.MyFunc(1,50)
SELECT * from dbo.MyFunc(100,2)
SELECT * from dbo.MyFunc(100,50)
--DROP TABLE Customer
Demo link: Rextester
Basically, you can run an IF Exists with your query to see if there is going to be any data. If so, go ahead and run your query. If not, do a select default row.
If Exists (your query)
(your query)
Else
SELECT 'query for default row'
I hope its clear your problem.
Happy Coding.Thanks

Matching all columns with all search phrases

I want to let a user search through all the columns in a table for a set of phrases defined in a textbox (split terms with whitespace).
So what first came to mind is finding a way in SQL to concatenate all the columns and just use the LIKE operator (for each phrase) in this result.
The other solution I thought of is writing an algorithm which takes all the phrases searched, and match them with all the columns.
So I ended up with the following:
String [] columns = {"col1", "col2", "col3", "col4"};
String [] phrases = textBox.Text.Split(' ');
I then took all the possible combinations of columns and phrases, and put that into a where-clause-format for sql and then the result was
"(col1 LIKE '%prase1%' AND col1 LIKE '%phrase2%') OR
(col1 LIKE '%phrase1%' AND col2 LIKE '%phrase2%') OR
(col1 LIKE '%phrase2%' AND col2 LIKE '%phrase1%') OR
(col2 LIKE '%phrase1%' AND col3 LIKE '%phrase2%')"
The above is just an example snippet of the output, the amount of conditions being created in this algorith is measured by
conditions=columns^(phrases+1)
So I observed that having 2 search phrases can still give good performance, but more than that will certainly decrease performance drastically.
What is the best practise when searching all the columns for the same data?
Edwin,
I didn't know you was using ORACLE. My solution is using SQL Server. Hopefully you will get the gist of the solution and translate into PL/SQL.
Hopefully this is useful to you.
I am manually populating the #search temp table. You will need to somehow do that. Or look for some Split Function that will take the delimited string and return a Table.
IF OBJECT_ID('tempdb..#keywords') IS NOT NULL
DROP TABLE #keywords;
IF OBJECT_ID('tempdb..#search') IS NOT NULL
DROP TABLE #search;
DECLARE #search_count INT
-- Populate # search with all my search strings
SELECT *
INTO #search
FROM (
SELECT '%ST%' AS Search
UNION ALL
SELECT '%CL%'
) T1
SELECT #search_count = COUNT(*)
FROM #search;
PRINT #search_count
-- Populate my #keywords table with all column values from my table with table id and values
-- I just did a select id, value union with all fields
SELECT *
INTO #keywords
FROM (
SELECT client_id AS id
,First_name AS keyword
FROM [CLIENT]
UNION
SELECT client_id
,last_name
FROM [CLIENT]
) AS T1
-- see what is in there
SELECT *
FROM #search
SELECT *
FROM #keywords
-- I am doing a count(distinct #search.Search). This will get me a count,
--so if I put in 3 search values my count should equal 3 and that tells me all search strings have been found
SELECT #keywords.id
,COUNT(DISTINCT #search.Search)
FROM #keywords
INNER JOIN #search ON #keywords.keyword LIKE #search.Search
GROUP BY #keywords.id
HAVING COUNT(DISTINCT #search.Search) = #search_count
SELECT *
FROM [CLIENT]
WHERE [CLIENT].client_id IN (
SELECT #keywords.id
FROM #keywords
INNER JOIN #search ON #keywords.keyword LIKE #search.Search
GROUP BY #keywords.id
HAVING COUNT(DISTINCT #search.Search) = #search_count
)
You could create a stored procedure or function in PL/SQL to dynamically search the table for the search terms and then bring back the primary key and column of any matches. The code sample below should be enough to tailor to your requirements.
create table text_table(
col1 varchar2(32),
col2 varchar2(32),
col3 varchar2(32),
col4 varchar2(32),
col5 varchar2(32),
pk varchar2(32)
);
insert into text_table(col1, col2, col3, col4, col5, pk)
values ('the','quick','brown','fox','jumped', '1');
insert into text_table(col1, col2, col3, col4, col5, pk)
values ('over','the','lazy','dog','!', '2');
commit;
declare
rc sys_refcursor;
cursor_num number;
col_count number;
desc_tab dbms_sql.desc_tab;
vs_column_value varchar2(4000);
search_terms dbms_sql.varchar2a;
matching_cols dbms_sql.varchar2a;
empty dbms_sql.varchar2a;
key_value varchar2(32);
begin
--words to search for (i.e. from the text box)
search_terms(1) := 'fox';
search_terms(2) := 'box';
open rc for select * from text_table;
--Get the cursor number
cursor_num := dbms_sql.to_cursor_number(rc);
--Get the column definitions
dbms_sql.describe_columns(cursor_num, col_count, desc_tab);
--You must define the columns first
for i in 1..col_count loop
dbms_sql.define_column(cursor_num, i, vs_column_value, 4000);
end loop;
--loop through the rows
while ( dbms_sql.fetch_rows(cursor_num) > 0 ) loop
matching_cols := empty;
for i in 1 .. col_count loop --loop across the cols
--Get the column value
dbms_sql.column_value(cursor_num, i, vs_column_value);
--Get the value of the primary key based on the column name
if (desc_tab(i).col_name = 'PK') then
key_value := vs_column_value;
end if;
--Scan the search terms array for a match
for j in 1..search_terms.count loop
if (search_terms(j) like '%'||vs_column_value||'%') then
matching_cols(nvl(matching_cols.last,0) + 1) := desc_tab(i).col_name;
end if;
end loop;
end loop;
--Print the result matches
if matching_cols.last is not null then
for i in 1..matching_cols.last loop
dbms_output.put_line('Primary Key: '|| key_value||'. Matching Column: '||matching_cols(i));
end loop;
end if;
end loop;
end;

Returning data which is not found in where clause and didn't update in sql

In a c# desktop application I am getting this list of data which I am reading by barcode into text file; here is the result;
R900, 27674T07, 27438T17, 27736T21, 26609T08,
R901, 27770T12, 27833T07, 26402T12, 27771T09, 26003T13,
R902, 26003T14, 26402T11, 26246T17,
R904, 28055T09, 25356T08, 25825T07, 25556T09,
and I am transforming it to update queries;
UPDATE TABLE SET NUMBER = R900 WHERE id in ( 27674T07, 27438T17, 27736T21, 26609T08)
UPDATE TABLE SET NUMBER = R901 WHERE id in ( 27770T12, 27833T07, **26402T12**, **27771T09**, 26003T13)
UPDATE TABLE SET NUMBER = R902 WHERE id in ( 26003T14, **26402T11**, 26246T17)
UPDATE TABLE SET NUMBER = R904 WHERE id in ( 28055T09, 25356T08, 25825T07, **25556T09**)
Finally I am executing this SQL query. But the problem is I don't know which id is not found in IN clause in database. I need to report back to user which id didn't found with its NUMBER
For example the bold id's are not found in database, and couldn't update. So expected result is:
NUMBER id
R901 26402T12
R901 27771T09
R902 26402T11
R903 25556T09
how can I return this?
You could do something like this
declare #mytable as TABLE
(
Id nvarchar(20)
)
UPDATE TABLE SET NUMBER = R900
OUTPUT INSERTED.Id into #mytable
WHERE id in ( 27674T07, 27438T17, 27736T21, 26609T08)
Select * from #mytable
#mytable will contain updated Ids only.
Hope this helps.
create a temp table to store the splitted value into it.
then
SELECT temp.number, temp.Id
FROM #temp temp
LEFT OUTER JOIN TABLE ON temp.id = TABLE.id
WHERE TABLE.id is null

Update a table from two comma separated parameter as input

I have a Gridview in front end where Grid have two columns : ID and Order like this:
ID Order
1 1
2 2
3 3
4 4
Now user can update the order like in front end Gridview:
ID Order
1 2
2 4
3 1
4 3
Now if the user click the save button the ID and order data is being sent to Stored Procedure as #sID = (1,2,3,4) and #sOrder = (2,4,1,3)
Now if I want to update the order and make save I want to store it into database. Through Stored procedure how can update into the table so that the table is updated and while select it gives me the results like:
ID Order
1 2
2 4
3 1
4 3
There is no built in function to parse these comma separated string. However, yo can use the XML function in SQL Server to do this. Something like:
DECLARE #sID VARCHAR(100) = '1,2,3,4';
DECLARE #sOrder VARCHAR(10) = '2,4,1,3';
DECLARE #sIDASXml xml = CONVERT(xml,
'<root><s>' +
REPLACE(#sID, ',', '</s><s>') +
'</s></root>');
DECLARE #sOrderASXml xml = CONVERT(xml,
'<root><s>' +
REPLACE(#sOrder, ',', '</s><s>') +
'</s></root>');
;WITH ParsedIDs
AS
(
SELECT ID = T.c.value('.','varchar(20)'),
ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS RowNumber
FROM #sIDASXml.nodes('/root/s') T(c)
), ParsedOrders
AS
(
SELECT "Order" = T.c.value('.','varchar(20)'),
ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS RowNumber
FROM #sOrderASXml.nodes('/root/s') T(c)
)
UPDATE t
SET t."Order" = p."Order"
FROM #tableName AS t
INNER JOIN
(
SELECT i.ID, p."Order"
FROM ParsedOrders p
INNER JOIN ParsedIDs i ON p.RowNumber = i.RowNumber
) AS p ON t.ID = p.ID;
Live Demo
Then you can put this inside a stored procedure or whatever.
Note that: You didn't need to do all of this manually, it should be some way to make this gridview update the underlying data table automatically through data binding. You should search for something like this instead of all this pain.
You could use a table valued parameter to avoid sending delimiter-separated values or even XML to the database. To do this you need to:
Declare a parameter type in the database, like this:
CREATE TYPE UpdateOrderType TABLE (ID int, Order int)
After that you can define the procedure to use the parameter as
CREATE PROCEDURE UpdateOrder (#UpdateOrderValues UpdateOrderType readonly)
AS
BEGIN
UPDATE t
SET OrderID = tvp.Order
FROM <YourTable> t
INNER JOIN #UpdateOrderValues tvp ON t.ID=tvp.ID
END
As you can see, the SQL is trivial compared to parsing XML or delimited strings.
Use the parameter from C#:
using (SqlCommand command = connection.CreateCommand()) {
command.CommandText = "dbo.UpdateOrder";
command.CommandType = CommandType.StoredProcedure;
//create a table from your gridview data
DataTable paramValue = CreateDataTable(orderedData)
SqlParameter parameter = command.Parameters
.AddWithValue("#UpdateOrderValues", paramValue );
parameter.SqlDbType = SqlDbType.Structured;
parameter.TypeName = "dbo.UpdateOrderType";
command.ExecuteNonQuery();
}
where CreateDataTable is something like:
//assuming the source data has ID and Order properties
private static DataTable CreateDataTable(IEnumerable<OrderData> source) {
DataTable table = new DataTable();
table.Columns.Add("ID", typeof(int));
table.Columns.Add("Order", typeof(int));
foreach (OrderData data in source) {
table.Rows.Add(data.ID, data.Order);
}
return table;
}
(code lifted from this question)
As you can see this approach (specific to SQL-Server 2008 and up) makes it easier and more formal to pass in structured data as a parameter to a procedure. What's more, you're working with type safety all the way, so much of the parsing errors that tend to crop up in string/xml manipulation are not an issue.
You can use charindex like
DECLARE #id VARCHAR(MAX)
DECLARE #order VARCHAR(MAX)
SET #id='1,2,3,4,'
SET #order='2,4,1,3,'
WHILE CHARINDEX(',',#id) > 0
BEGIN
DECLARE #tmpid VARCHAR(50)
SET #tmpid=SUBSTRING(#id,1,(charindex(',',#id)-1))
DECLARE #tmporder VARCHAR(50)
SET #tmporder=SUBSTRING(#order,1,(charindex(',',#order)-1))
UPDATE dbo.Test SET
[Order]=#tmporder
WHERE ID=convert(int,#tmpid)
SET #id = SUBSTRING(#id,charindex(',',#id)+1,len(#id))
SET #order=SUBSTRING(#order,charindex(',',#order)+1,len(#order))
END

Categories

Resources