select rows not contained in table - c#

I have a table containing an ID as follows:
ID
----------------
10000V9F
10000V9O
10000VAh
10000VCB
10000VDn
10000VE9
10000VF4
10000VFE
10000VFH
10000VFW
10000VG9
Now I want to get all the data from another table that has none of these IDs. Therefor I create a query similar to this one:
SELECT * from TABLE1 where ID NOT IN (...)
Where ... is a list of IDs a got via another query and that contains all the previously mentioned IDs from the first table. This list is defined as follows:
string idString = "'" + String.Join("'", this.GetIDsForTableNames(newTables).ToArray()) + "'";
The method GetIDsForTableNames may also return an empty list containing no elements at all. In this case the resulting query from above would lead to something like this:
SELECT * from TABLE1 where ID NOT IN ('')
Which I expect to return ALL the IDs from TABLE1. But instead NONE is returned. However when I fire SELECT * from TABLE1 where ID NOT IN ('a') where a is just a dummy all rows from TABLE1 are returned.
So how can I handle the list-is-empty-case appropriatly or why doesn´t it work with an empty list?
EDIT: Okay, it seems some surroundings are not clear enough. As I´m not building the SQL-string self (this is done via 3rd-party tool), I can only modify the whereclause which is only some kind of minimzed SQL (subqueries and joins NOT supported). This is why I used the ID IN-technic.

why doesn´t it work with an empty list?
That's because of 2 things:
1. Oracle treats empty strings as null values
So your query:
SELECT * from TABLE1 where ID NOT IN ('')
is in fact equivalent to:
SELECT * from TABLE1 where ID NOT IN (NULL)
2. NOT IN behavior
The NOT IN clause can be simplified as a check of all values against the list.
If the result of any value is TRUE (the value is in the list) or NULL, then the test fails.
All the checks returns NULL, so your query doesn't return any row.
This is why it doesn't work with an empty list in Oracle.
Back to your question:
how can I handle the list-is-empty-case appropriatly
You have to find another way than getting the IDs and including them in a NOT IN clause.
As you don't have any control on the query, you will have to include details on your 3-party tool and hope there is a workaround.
More info about this:
Oracle/PLSQL: Difference between an empty string and a null value
Understand how NULLs affect IN and EXISTS
NULLs in Oracle
Note: (just in case some SQL Server users find this post)
If you were using SQL Server, your query would work because empty strings are not processed as NULL.
Even the second query SELECT * from TABLE1 where ID NOT IN (NULL) would work assuming you have set ANSI_NULLS to OFF. Such a setting is not available in Oracle.

Related

LINQ queries always sort by primary key value even when orderby clause explicitly calls to sort with a different value

I am working on my first personal C# project and am incorporating LINQ to make queries against a SQL Server database. I am experiencing an issue with LINQ where queries always sort the records returned from the table according to their primary key value even though orderby clauses exist in the query.
My objective is to query a table that includes columns for first name and last name (both of type varchar); sort by first name; then sort by last name. The problem code consists of two sections. The first is the original query:
var dayShiftCrew =
from information in context.EmployeeInformations
where information.EmployeeShiftType.Shift == "Day" && information.EmployeePositionType.Position == "Crew"
orderby information.EmployeeNamesAndNumber.FirstName, information.EmployeeNamesAndNumber.LastName
select information.EmployeeNamesAndNumber;
The second part is a foreach statement that populates another table with the query results:
foreach (var employee in dayShiftCrew)
{
var position =
from selection in context.EmployeeInformations
where selection.EmployeeID == employee.EmployeeID
select selection.Position;
string query2 = $#"USE Employees; INSERT INTO WeeklySchedule_{month}_{day}_{year} " +
#"(EmployeeID, Name, Position) VALUES " +
$#"({employee.EmployeeID}, '{employee.FirstName + (" ") + employee.LastName}', '{position.First()}');";
SqlCommand command2 = new SqlCommand(query2, connection);
command2.ExecuteNonQuery();
}
When I view the destination table after it is populated, the records are not arranged according to the query's orderby clause. I have executed variations of this code multiple times, and each time the records appear in the same sequence. The sequence in the destination table matches the sequence in the original table, which leads me to think that either the query is sorting by the records' primary key value or is not sorting at all and simply returning the records in their original sequence.
I'm sure that there is something that I'm overlooking, but I have been experimenting for a while with this code and cannot find a solution to sort correctly. I have tried both kinds of syntax for LINQ queries; tried using one orderby rule instead of two; and rewrote lines for immediate instead of deferred execution.
Other specific details: The from clause refers to a table with a composite primary key that includes four foreign-key relationships. The query returns an IQueryable that contains the desired records, albeit in the wrong order. No exceptions are thrown at compile or runtime, and no other unexpected behavior is occurring apart from this.

I need to add a tinyint value in the result of a SELECT

It's 2 days that i'm torned with this task and i can't really find a solution since i'm not an expert of MySQL. So basically i have this query
sql.Append("select distinct ");
sql.Append(#"{0}.field1,
{0}.field2,
{0}.field3,
{0}.field4,
{0}.field5,
---
---
false as customField1,
false as customField2,
{1}.name as customfield3
from {0} join {1} on {0}.field2check = {1}.id where field2check = ?condition");
this is the text of a select that i'm building in my c# class. This query is then completed and feeded to the database, that give me in response a table that is stored in a DataTable. My problem is that this fields
false as customField1,
false as customField2,
{1}.name as customfield3
are actually obtained after the evaluation of a condition and must return a tinyint(1) to be interpreted as boolean in my c# code, since the bool type don't exist in my sql. If i write directly 0 or 1, this value is casted as BIGINT that is interpreted as Int32 in c#.
I know that i can create a custom function to be stored in my db like
CREATE FUNCTION myDb.x_cast_to_tinyint(number bigint) RETURNS tinyint(1)
return number;
But this is forbidden in my case (my boss simply don't want to save function in db). Now i was looking to create a temporary table to store the result of this query, but the problem is that i have no clue on how to do that. Something like
create temporary table myDB.res (customfield1 tinyint(1).... ) as (put the select here)
The problems here are 2. First i don't know how to define all the columns of this table, cause it should have the same structure of an existing table plus 3 custom columns. Even if i successfully create this table, how long does it last?. Can i query this table to select * from it?
I am open also to other solutions. If you need other details let me know
EDIT : forgot to mention this. The c# part should remain untouched. I thought to make a converter for those specific column of my datatable but also this solution received a big no in response (and i'm in part good with it, case my c# code should only represent the data, and shouldn't know anything about the structure of the database)
You could try something like this, although I think it's more complex than adding a function:
CREATE TEMPORARY TABLE myTempTable LIKE theFirstTable;
ALTER TABLE myTempTable
ADD COLUMN customField1 TINYINT(1),
ADD COLUMN customField2 TINYINT(1),
ADD COLUMN customField3 TINYINT(1);
INSERT INTO myTempTable
SELECT o.*, customField1, customField2, customField3
FROM originalTable o...
Obviously, you have to customize this approach to your needs, but the advantage is that temporary table will last until the connection is closed or you explicitly drop it.

SQL Server where using multiple data types

I couldn't come up with a better title.
I have a list of values like:
List<string> ids = new List<string>() {"1", "AND", "2", "NOT", "3"}
And a database table which contains the ids specified in the list above.
My problem is that I need to retrieve the data based on the ids, including the values which are not found in the table ( the operators AND and NOT for the list above).
For example, using the list above, after reading the db values for 1,2 and 3 a new list will be created like:
List<string> values = {"Value1", "AND", "Value2", "NOT", "Value3"}
The operators, AND, OR, NOT, ) and ( are just simple strings which are not found in MyTable.
Until now I was splitting the ids and for each value I do a trip to the db and get the value. The problem with this is that it takes a lot of time even for 2k lists. A list has around 10 values each.
What I was thinking about is to use the where in clause which will hopefully reduce the trips to the database. Unfortunately, I don't know how to handle the operators from the first list. (The operators are not saved in MyTable ).
I've tried using multiple where conditions but I cannot convert the operators (which are strings) to int (type of the Id column).
Queries I've tried:
SELECT Title
FROM MyTable where Id =1 or Id = cast('AND' as int)
And
SELECT Title
FROM MyTable where Id in (1,2,'AND')
Both of them fail (rightfully) because sql cannot convert AND to data type int.
What I want is to use the where clause (or any other) for the first list and where there is no result found in the db return the value used in the query.
For example, for the query:
SELECT Title
FROM MyTable where Id in (1,2,'AND')
I'd like to receive from the db Value1, Value2, AND. I know that the order is not guaranteed when executing the query.
How could I solve this problem efficiently? I'm using c# with sql server 2012 without any orm
First, you need to extract those list entries which need to be converted, i.e. your search keys, from the list.
Once done, you can query those like so:
select id, title from MyTable where id in ( /* list goes here*/)
Load the results of the query into a Dictionary<int,string>.
Then, go over the list a second time, replacing the keys with the values from your dictionary.
If you find that the SQL query performs badly you should look at indexes and query hints, or ask again for a faster query.
Why this might improve performance
The main reason is it will reduce trips to the database. However if the database is on the same physical machine this is unlikely to be significant.
Alternatively, if the list of keys and titles does not change often, and it's OK for it to be slightly out of date, you might load the whole thing into a dictionary. 100,000 entries is not that many - if they are 50 bytes each that's only 5 MB which is not very much on a modern server.
You can try to cast the Id in your SQL-Query
SELECT Title
FROM MyTable where cast(Id as nvarchar) in (1,2,'AND')
but this would greatly reduce your performance

How to include an 'order' or 'index' column in a SELECT query?

I'm using Access SQL. I want to add a column to my query that acts like a row number for each record, but because I'm using an aggregate function, the results have not ids themselves. Is there any function that generate some row numbers for this ? even like Autonumber or index or just the order. So my dummy SQL syntax is like:
SELECT [wanted autonumber column], product,Sum(amount) FROM Invoices_Items GROUP BY product
I guessed maybe it would be good if I create a temporary table for this query with an autonumber column but I don't know how to that.
If you save the GROUP BY SQL as a named query in Access, you can use that as the data source for another SELECT statement which uses a correlated subquery to generate a row number.
So with this SQL saved as qryInvoices_Items1 ...
SELECT i.product, Sum(i.amount) AS SumOfamount
FROM Invoices_Items AS i
GROUP BY i.product;
This query will add a dynamic row number --- the row number for a given product can be different from one run to the next if the underlying Invoices_Items data changes.
SELECT
(
SELECT Count(*)
FROM qryInvoices_Items1 AS q2
WHERE q2.product <= q1.product
) AS row_number,
q1.product,
q1.SumOfamount
FROM qryInvoices_Items1 AS q1;
I tested that SQL in Access 2007, and it returns the result I think you're looking for. However, if I'm wrong about that point, please include Invoices_Items sample data in your question (as text, not a screen capture image) and show us the output you want based on that sample data.
Note a correlated subquery requires the db engine run that subquery separately for each row of the parent query's result set. That would be a big performance challenge with a huge data set. However, if your data set is small enough, the perform impact could be tolerable, or maybe not even noticeable.

Retrieving records from table where a column may have multiple rows of data

I have a database with several tables and I am using the following query to return a record that matches a string(Name).
In the MHP table there is a Name field(primary key), Num_Sites and a few more, but these are the only ones I am concerned with.
In the MHP_Parcel_Info table there are many fields with one of them being Name(foreign key). There is a parcel_id field and in some case there may only be one parcel for one name, but there may also be many parcels for a Name.
As it is now my query will return one of the rows for instances where there are multiple parcels for a name.
What I would like to do is: if there is more than one parcel for a Name, have all the parcels put into a list(so I can display in listbox on form).
My SQL skills are limited and I don’t know how I would go about doing something like this.
SELECT MHP_Parcel_Info.*, MHP.NUM_SITES FROM MHP_Parcel_Info INNER JOIN MHP ON " +
"(MHP_Parcel_Info.MHP_NAME = MHP.MHP_NAME) WHERE MHP_Parcel_Info.MHP_NAME='" + strValue + "'"
This is not something you can do directly in SQL. There's no way to select data in a parent/child structure in a SQL query - you have to do that as a post-processing step.
Since this is tagged as C# and Winforms I'm assuming this is from inside a .Net app. You will need to execute the query as you have it above, then in C# you can use the LINQ GroupBy extension method on the result to group the results into a list of IGrouping objects which use the name as the key, and has all of the parcel info as the items in the list.
Even better, if you are using (or can use) LINQ to SQL or Entity Framework you can just write a linq query that fetches the data from the database and does the grouping all at once.

Categories

Resources