Replace the following query in sqlite - c#

I have a sql server query as follows in a store procedure with parameters #firstId and #secondId
IF #firstId = ''
begin
SELECT DISTINCT x, y =
FROM t1
LEFT OUTER JOIN t2 ON t1.id = t2.id AND t2.id = #secondId
ORDER BY t1.somecolumn
END
ELSE
BEGIN
SELECT DISTINCT x, y =
FROM t1
LEFT OUTER JOIN t2 ON t1.id = t2.id AND t2.id = #secondId
AND t1.id = #firstId
ORDER BY t1.somecolumn
END
I am very new to sqlite and trying to write the above query in sqlite with case statements as suggested in the sqlite documentation but so far not able to achieve the same. I want achieve something like below or a better query.
CASE WHEN #firstId = '' THEN (CHOOSE FIRST SELECT STATEMENT) ELSE (CHOOSE SECOND SELECT STATEMENT) END
I thought of splitting the original sql query into two select statements in sqlite and call respective query based on the condition handled in c# code base file as shown below but not sure if this is the good practice.
if(firstId == string.empty)
{
//call the first select statement
}
else
{
//call the second select statement
}
I don't want to split the store procedure into two separate queries. Any help is appreciated.

You can do in one go. Above 2 statements are equivalent to this:
SELECT DISTINCT x, y
FROM t1
LEFT OUTER JOIN t2 ON t1.id = t2.id AND t2.id = #secondId
AND (t1.id = #firstId OR #firstId = '')
ORDER BY t1.somecolumn

Related

How do I define JOIN precedence in SqlKata

I'm using SqlKata in my project and it's necessary to connect several tables with the help of nested join. I expect to see something like that:
SELECT * FROM t1
LEFT JOIN (t2 LEFT JOIN t3 ON t3.id = t2.id)
ON t2.id = t1.id
In Join/LeftJoin/RigthJoin methods, I did not find any overloads that would accept anything other than a join or other request.
Wouldn't want to manually make such connections, maybe someone has already faced such a problem? That would be great, I would really appreciate a hint.
Defining JOIN precedence is not available in SqlKata at the moment.
But you can achieve same result by using a Sub Query.
var query = new Query("t1")
.LeftJoin(
new Query("t2").LeftJoin("t3", "t3.id", "t2.id").As("tmp"),
j => j.On( "tmp.id", "t1.id")
);
This query would result in the following sql:
SELECT * FROM [t1] LEFT JOIN (
SELECT * FROM [t2] LEFT JOIN [t3] ON [t3].[id] = [t2].[id]
) AS [tmp] ON ([tmp].[id] = [t1].[id])

Convert linq to SQL

Does anyone know how to translate this? When I hit the debugger I get 3 different queries and var contains an array of results. I am trying to replace that line with a method that will call a stored procedure but I do not understand what the query should be. Thanks a lot
var restbl =
context.tbl_one.FirstOrDefault(d => d.qty < d.tbl_two.Count(a => !a.tbl_three.ust))
?? context.tbl_one.FirstOrDefault(d => d.qty > d.tbl_two.Count(a => !a.tbl_three.ust));
{SELECT
`Extent1`.`id`,
`Extent1`.`name`,
`Extent1`.`qty`,
`Extent1`.`cdate`
FROM `tbl_one` AS `Extent1`}
{SELECT
`Extent1`.`id`,
`Extent1`.`tbl_one_id`,
`Extent1`.`tbl_three_id`,
`Extent1`.`enabled`
FROM `tbl_two` AS `Extent1`}
{SELECT
`Extent1`.`id`,
`Extent1`.`ttid`,
`Extent1`.`code`,
`Extent1`.`cdate`,
`Extent1`.`mdate`,
`Extent1`.`prt`,
`Extent1`.`ust`
FROM `tbl_three` AS `Extent1`}
var countToAdd = restbl.qty - context.tbl_two.Count(a => a.tbl_one_id == restbl.id && !a.tbl_three.ust);
You can use LINQPad or Linquer tool for easily converting your linq query to SQL or vice versa. They are very helpful in converting complex queries.
My assumption would be: (assuming you use MSSQL)
result= SELECT TOP 1 FROM tbl_one t1 WHERE t1.qty< (SELECT COUNT(*) FROM tbl_two t2 INNER JOIN tbl_three t3 ON t3.id=t2.tbl_three_id WHERE t3.ust = 0 AND t1.id=t2.tbl_one-id)
if (result IS NULL)
result= SELECT TOP 1 FROM tbl_one t1 WHERE t1.qty> (SELECT COUNT(*) FROM tbl_two t2 INNER JOIN tbl_three t3 ON t3.id=t2.tbl_three_id WHERE t3.ust = 0 AND t1.id=t2.tbl_one-id)

How do I write an exists subquery using multiple columns in LINQ?

I am trying to write a linq query that resembles this SQL:
SELECT * FROM Table1
WHERE EXISTS (
SELECT 1 FROM Table2
WHERE Table1.ColA = Table2.ColA
AND Table1.ColB = Table2.ColB
)
Except Table2 is an object list I already have previously from the database.
I know how to use contains() to emulate an SQL "IN SUBQUERY" using a object list outside of the database when one column is involved:
var query = from t1 in db.Table1
where MyObjList.Select(o => o.Field1).Contains(t1.Col1)
select t1;
I figure I can do a join in Linq. But will that perform ok? I hope avoid a database call per object in my list.
var q = from t1 in db.Table1
from t2 in db.Table2.Where(x => x.ColA == t1.ColA && x.ColB == t1.ColB)
select t1;
Try like this:
var query = from t1 in db.Table1
join t2 in db.Table2 on t1.ColA equals t2.ColA
Where t1.ColB == t2.ColB
Select t1;
OR without Join
var query = from t1 in db.Table1
from t2 in db.Table2
Where t1.ColA == t2.ColA && t1.ColB == t2.ColB
Select t1;

Query in Ms Access, how to make a chain of joins (with its own criteria) that only show up if the first part of the join exists

I'm trying to make a query that makes a new table from 7 different tables, and then I need to use this query in a C# program, so I wouldn't be able to make 2 queries to do this.
How would I make a join that only shows up if the two parts of the join are equal, and if it does show up, it gets more info from a third table and only really shows up if one of its columns in the third table equals 2.
For example, I have a lot of different joins, and at one part, Table 1, I join it to Table 2. I want everything from table 1 to show up, and only the matching ones from table 2. and if table 1 and 2 match, the info in table 2 only shows up if it fits a certain criteria from table 3, which is join to table 2.
I hope that makes sense?
Thanks!
EDIT
okay the main problem is am I able to set criteria that only happens for a certain join and not the whole query?
From the info you have provided it sounds like you want to left join table 2 to table 1, and inner join table 3 to table 2, using your criteria.
for example, i have alot of different joints, and at one part, Table 1, i join it to Table 2.
Ok, you want Table 1 to join to Table 2.
I want everything from table 1 to show up, and only the matching ones from table 2.
This is called a Left Join from Table1 to Table2. A Left Join returns all records from the left hand table, even if there is no matching record in the right hand table.
So, so far we have
SELECT *
FROM Table1 T1
LEFT JOIN Table2 T2 ON T1.ID = T2.ID
and if table 1 and 2 match, the info in table 2 only shows up if it fits a certain criteria from table 3, which is joint to table 2.
This means you want an inner join between Table2 and Table3. An Inner Join returns all records that match both the left and right hand tables. Let's combine this with our first query:
SELECT *
FROM Table1 T1
LEFT JOIN Table2 T2 ON T1.ID = T2.ID
INNER JOIN Table3 T3 ON T3.ID = T2.ID
However, this won't work. This only returns records that match all 3 tables because the Inner Join is applied to the result from the first Left Join.
What you need in this circumstance is a derived table. You can get one by using the following query:
SELECT *
FROM #Table1 T1
LEFT JOIN (
SELECT T2.ID as T2ID, T2.HairColor as HairColor, T3.ID as T3ID, T3.Age as Age FROM #Table2 T2
INNER JOIN #Table3 T3 ON T3.ID = T2.ID
WHERE T3.Age = 3
) as T2SubSet ON t1.ID = T2SubSet.T2ID
This is evaluated by creating the subset of table 2/3 that you are looking for and then taking the result of that query and joining it to table 1 with a left join. For a full complete example, you can use the following query:
DECLARE #Table1 TABLE(
ID int,
Name varchar(10))
DECLARE #Table2 TABLE(
ID int,
HairColor varchar(10))
DECLARE #Table3 TABLE(
ID int,
Age int)
INSERT INTO #Table1 values (1, 'John'), (2, 'Mary'), (3,'Sue')
INSERT INTO #Table2 values (1, 'Red'), (2, 'Brown'), (3, 'Black')
INSERT INTO #Table3 values (1, 3), (2, 5), (4,8)
SELECT *
FROM #Table1 T1
LEFT JOIN #Table2 T2 ON T1.ID = T2.ID
INNER JOIN #Table3 T3 ON T3.ID = T2.ID
SELECT *
FROM Table1 T1
LEFT JOIN (
SELECT T2.ID as T2ID, T2.HairColor as HairColor, T3.ID as T3ID, T3.Age as Age FROM Table2 T2
INNER JOIN Table3 T3 ON T3.ID = T2.ID
) as T2SubSet ON t1.ID = T2SubSet.T2ID
I also just noticed you said:
columns in the third table equals 2.
This can be done by adding another 'On' statement like 'T3.Column = 2' Using my last query above, it would be
SELECT *
FROM #Table1 T1
LEFT JOIN (
SELECT T2.ID as T2ID, T2.HairColor as HairColor, T3.ID as T3ID, T3.Age as Age FROM #Table2 T2
INNER JOIN #Table3 T3 ON T3.ID = T2.ID AND T3.Age = 2
) as T2SubSet ON t1.ID = T2SubSet.T2ID

sql join problem with negatives

I need to select data from two table using a join. This is fairly simple and have no problems here. The problem occurs when the field I am joining is used as two separate foreign keys (I didn't design this). So the ID field that I join on is either a positive or negative number.
If it's a positive number it relates to ID_1 on the table_2 table, if it's a negative, the number relates to ID_2 on the table_2 table. However the ID_2 will be a positive number (even though it's stored as a negative in the foreign key). Obviously there are no constraints to enforce these - so in essence not real foreign keys :/
The SQL I'm using goes something like this and is fine for the positive numbers:
select t1.Stuff, t2.MoreStuff from table_1 t1
join table_2 t2 on t1.ID_1 = t2.ID_1
where ...
How to incorporate the negative aspect of this into the join. Is this even possible? Ideally I'd like to alter the table to my needs but apparently this is not a valid option. I'm well and truly stuck.
The only other idea I've had is a separate sql statement to handle these odd ones. This is all being run by clr sql from C#. Adding a separate SqlCommand to the code will most likely slow things down hence why I'd prefer to keep it all in one command.
Your input is welcome, thanks :)
Let's say the tables look like this:
Table1 (id INT, foo INT, fk INT)
Table2 (id1 INT, id2 INT, bar VARCHAR(100))
...where fk can be used to look up a row in Table2 using id1 if positive and id2 if negative.
Then you can do the join as follows:
SELECT T1.id, T1.foo, T2.bar
FROM Table1 T1 INNER JOIN Table2 T2
ON (T1.fk > 0 AND T2.id1 = T1.fk)
OR (T1.fk < 0 AND T2.id2 = - T1.fk)
Simpliest way - join these tables using UNION ALL:
select t1.Stuff, t2.MoreStuff from table_1 t1
join table_2 t2 on t1.ID_1 = t2.ID_1
where t1._ID_1>0
UNION ALL
select t1.Stuff, t2.MoreStuff from table_1 t1
join table_2 t2 on abs(t1.ID_1) = t2.ID_2
where t1._ID_1<0
This won't be very performant...but then, nothing will. You need to transform your negative key into a positive one, and conditional logic for the join. Like this:
select t1.Stuff, t2.MoreStuff
from table_1 t1
join table_2 t2 on (t1.ID_1 > 0 AND t1.ID_1 = t2.ID_1)
OR (t1.ID_1 <0 AND ABS(t1.ID_1) = t2.ID_2)
where ...
No chance of using an index, because you're transforming t1.ID_1 (with the ABS function), but it's the best that you can do given the circumstances.
You can do something like this, but only after introducing the schema designer to a LART:
SELECT
t1.stuff, COALESCE(t2a.morestuff, t2b.morestuff)
FROM
table_1 t1
LEFT JOIN table_2 t2a ON (t1.id_1 > 0 AND t1.id_1 = t2a.id_1)
LEFT JOIN table_2 t2b ON (t1.id_1 < 0 AND t1.id_1 = -1 * t2b.id_2)
// etc
Alternatively,
SELECT
t1.stuff, t2.morestuff
FROM
table_1 t1
LEFT JOIN table_2 t2 ON (
(t1.id_1 > 0 AND t1.id_1 = t2.id_1)
OR (t1.id_1 < 0 AND t1.id_1 = -1 * t2.id_2)
)
// etc
Remember the LART, that's the most important part!
try this
DECLARE #Table TABLE(
ID INT,
ForeignKeyID INT
)
INSERT INTO #Table (ID,ForeignKeyID) SELECT 1, 1
INSERT INTO #Table (ID,ForeignKeyID) SELECT 2, 2
INSERT INTO #Table (ID,ForeignKeyID) SELECT 3, -1
INSERT INTO #Table (ID,ForeignKeyID) SELECT 4, -2
DECLARE #ForeignTable TABLE(
ID_1 INT,
ID_2 INT,
Val VARCHAR(MAX)
)
INSERT INTO #ForeignTable (ID_1,ID_2,Val) SELECT 1, 11, '1'
INSERT INTO #ForeignTable (ID_1,ID_2,Val) SELECT 2, 22, '2'
INSERT INTO #ForeignTable (ID_1,ID_2,Val) SELECT 3, 1, '3'
INSERT INTO #ForeignTable (ID_1,ID_2,Val) SELECT 3, 2, '4'
SELECT *
FROM #Table t INNER JOIN
#ForeignTable ft ON ABS(t.ForeignKeyID) =
CASE
WHEN t.ForeignKeyID > 0
THEN ft.ID_1
ELSE
ft.ID_2
END
It will have to be something like
select t1.Stuff, t2.MoreStuff from table_1 t1, table_2 t2 where (t1.ID_1 = t2.ID_1 OR t1.ID_1 = CONCAT("-",t2.ID_1)) where ...
Not sure if I have misunderstood your question.
By applying left joins across table two and using the absolute value function, you should be able to accomplish what you're looking for:
SELECT t1.Stuff, isnull(t2.MoreStuff, t2_2.MoreStuff)
FROM table_1 t1
LEFT JOIN table_2 t2 ON t1.ID_1 = t2.ID_1
AND t1.ID_1 > 0
LEFT JOIN table_2 t2_2 ON abs(t1.ID_2) = t2_2.ID_2
AND t1.ID_2 < 0
WHERE
...
The caveat here is that if ID_1 and ID_2 are not mutually exclusive you will get 2 query results.
select t1.Stuff, t2.MoreStuff from table_1 t1
join table_2 t2 on t1.ID_1 = t2.ID_1 or -t1.ID_1 = t2.ID_2
where ...

Categories

Resources