SQL statement that only fetches the newest department which has been allocated - c#

In my database i have the following rows and columns: https://i.imgur.com/ktUZY9d.jpg
My problem is the same employee has 3 different departments, but he is currently only active in 1. How do I change this SQL statement to only include the latest department he is in, which started in 2018 and ends in 2100, as seen by the ALLOCATION_START and ALLOCATION_END?
Query
string agentIdSubQuery = "SELECT DISTINCT " +
"AGENT_ID " +
"FROM " +
"KS_DRIFT.V_AGENT_ALLOCATION " +
"WHERE " +
"LENGTH(AGENT_INITIALS) < 5";
if(queryParams.SnapshotDate.HasValue)
agentIdSubQuery += " AND " + OracleConversion.ToOracleDate(queryParams.SnapshotDate) + " BETWEEN ALLOCATION_START AND ALLOCATION_END";
Update:
Tried alot of different solutions, but it crashes everytime, when i run through the debugger, further Down in this method this Query is causing me to crash:
string sql = "SELECT " +
"age1.* " +
"FROM " +
"KS_DRIFT.V_AGENT_ALLOCATION age1 " +
"INNER JOIN " +
"(" + agentIdSubQuery + ") age2 ON age1.AGENT_ID = age2.AGENT_ID " +
"ORDER BY " +
"AGENT_INITIALS";
Error Message:
{"Error occured during execution of SQL query: SELECT age1.* FROM KS_DRIFT.V_AGENT_ALLOCATION age1 INNER JOIN (SELECT max(DISTINCT AGENT_ID FROM KS_DRIFT.V_AGENT_ALLOCATION WHERE LENGTH(AGENT_INITIALS) < 5 AND '2018-08-15' BETWEEN ALLOCATION_START AND ALLOCATION_END AND (UPPER(AGENT_INITIALS) = 'JKKA')) age2 ON age1.AGENT_ID = age2.AGENT_ID ORDER BY AGENT_INITIALS."}
Also giving me an inner exception:
{"ORA-00904: \"AGE2\".\"AGENT_ID\": ugyldig identifikator"}
Debugging error screeenshot

Order it by the newest start date (descending) and select Top 1!
string agentIdSubQuery = "AGENT_ID " +
"FROM " +
"KS_DRIFT.V_AGENT_ALLOCATION " +
"WHERE " +
"LENGTH(AGENT_INITIALS) < 5 " +
" AND ROWNUM = 1 " +
" ORDER BY ALLOCATION_START DESC";
EDIT, changed Top 1 to Rownum = 1, for Oracle syntax

The table V_AGENT_ALLOCATION contains various departments per agent along with the dates the agent worked there. You want an agent's last department, which you get with Oracle's KEEP LAST. You haven't given us much information on your table, though. Let's say that the department is referenced by an allocation_id:
select
agent_id,
max(id_allocation) keep (dense_rank last order by allocation_start)
as id_current_allocation
from v_agent_allocation
group by agent_id
order by agent_id;

Your error message shows the final generated SQL:
{"Error occurred during execution of SQL query: SELECT age1.* FROM KS_DRIFT.V_AGENT_ALLOCATION age1 INNER JOIN (SELECT max(DISTINCT AGENT_ID FROM KS_DRIFT.V_AGENT_ALLOCATION WHERE LENGTH(AGENT_INITIALS) < 5 AND '2018-08-15' BETWEEN ALLOCATION_START AND ALLOCATION_END AND (UPPER(AGENT_INITIALS) = 'JKKA')) age2 ON age1.AGENT_ID = age2.AGENT_ID ORDER BY AGENT_INITIALS."}
If you format that so that it's readable, you get:
select age1.*
from ks_drift.v_agent_allocation age1
inner join
( select max(distinct agent_id
from ks_drift.v_agent_allocation
where length(agent_initials) < 5
and '2018-08-15' between allocation_start and allocation_end
and (upper(agent_initials) = 'JKKA') ) age2
on age1.agent_id = age2.agent_id
order by agent_initials
Two syntax issues should jump out:
There is a missing closing bracket after max(distinct agent_id (the distinct is also redundant)
The date literal is missing its date keyword - it should be date '2018-08-15' (or better still, a bind variable).
The brackets around (upper(agent_initials) = 'JKKA') are redundant but perhaps they arise from your generator logic and it's easiest to keep them.
I'm not sure how that relates to your 'newest allocated department' requirement, though. Some sample data (not a screenshot) would help.

If you're looking for the current department, you should compare the allocation dates with the current date.
Your query already has this WHERE clause, so it should work just fine for the example provided. But if you might want to specify that you need only ONE row using the ROWNUM special variable clause (assuming it's Oracle).
SELECT DISTINCT AGENT_ID
FROM KS_DRIFT.V_AGENT_ALLOCATION
WHERE LENGTH(AGENT_INITIALS) < 5
AND ALLOCATION_START < CURRENT_DATE AND CURRENT_DATE < ALLOCATION_END
AND ROWNUM = 1

Related

Xamarin sql using left join for an android Tablet app

var db = new SQLiteConnection(dbPath);
try
{
var results = db.Query<Xclass>("SELECT X.COL1, X.COL2, " +
" X.COL3, X.Col4, X.Col5, " +
" A.Col2, A.COL3, B.Col2, C.Col2 " +
"FROM left join Xam X " +
"left join TABLE1 A on X.COL1 = A.COL1 " +
"left join TABLE2 B on X.COL2 = B.COL1 " +
"left join TABLE3 C on X.COL3 = C.COL1 " +
"WHERE X.COL1 ='"+ somevalue +"'");
}
catch (Exception e)
{
// display message
}
XCLASS Contains all the getters and setters.
But it only pulls in the Xam table and not the A, B, or C table values.
I originally had the table name in the Class but took it out to see if that would help.
Any assistance is appreciated. I am trying to avoid linq but if is necessary I will try it.
The instance(s) of Xclass object is created from the results of your query via reflection.
The columns in query's result set are translated to properties of the class
and the setters of hese properties are used to assign their values.
Therefore you must supply some hints to SQlite so it will know which column corresponds to which property. This is done via as keyword.
So, if you want assign the value of A.COL2 column in the result to property named MyCol2Property inside Xclass, you must retrieve it in the query using the syntax
A.Col2 as MyCol2Property

Which Join is needed for this query in SQL Server

I need to return paginated results i.e the second five records from a table called properties. This works alone with this query:
SELECT
Property_ID,
Property_Type,
Address_Line,
Area,
Postcode,
Weekly_Rate
FROM
dbo.Properties
WHERE
Area LIKE '%" + value + "%'
ORDER BY
Property_ID
OFFSET " + (start*end) + " ROWS
FETCH NEXT " + end + " ROWS ONLY"
The above code is written with C# added.
But I also need the first Image ID from the Images table that references each record returned in the paginated subset.
I tried a FULL OUTER JOIN and it didn't return what was expected, maybe because there is more than one image per property.
Any solutions to this would be great!
Thanks
This seems to nearly work but it's returning an error:
SELECT
dbo.Properties.Property_ID, Property_Type, dbo.Images_Table.[URL]
FROM
dbo.Properties p
OUTER APPLY
(SELECT TOP 1 i.*
FROM dbo.Images_Table i
WHERE i.Property_ID = p.Property_ID
ORDER BY i.Image_ID) i
WHERE
p.Area LIKE '%po%'
ORDER BY
p.Property_ID
OFFSET 0 ROWS
FETCH NEXT 5 ROWS ONLY
This is the error returned :
Msg 4104, Level 16, State 1, Line 1
The multi-part identifier "dbo.Properties.Property_ID" could not be bound.
Msg 4104, Level 16, State 1, Line 1
The multi-part identifier "dbo.Images_Table.URL" could not be bound.
You can use outer apply:
SELECT . . . , i.??
FROM dbo.Properties p OUTER APPLY
(SELECT TOP 1 i.*
FROM images i
WHERE i.Property_ID = p.Property_ID
ORDER BY i.Image_ID
) i
WHERE p.Area LIKE '%" + value + "%'
ORDER BY p.Property_ID
OFFSET " + (start*end) + " ROWS
FETCH NEXT " + end + " ROWS ONLY";
This is a bit speculative on how you are ordering the images. You also need to fill in the columns you want from the images table.

SQL Returning rows with max value in column, within a specific range

I'm populating a DataTable in C# using an OleDbDataAdapter, and I am trying to get a query to work without much success.
The communication to/from the server works fine, as is evidenced by the simple query that returns all the records without any filter:
var commandText = string.Format("SELECT IsoShtRevID, LineID, Filename, Revision " +
"FROM dbo.PDSIsometricSheets WHERE SchemaName='{0}'", projectNo);
This gives me a list of about 8000 entries, however there is some redundancy.
There are multiple rows with the same LineID, but each one has a separate Revision value. I'm trying to get only the rows with the highest revision for each LineID, from a range of 0 to 5.
Here are a few of the attempts I've tried so far:
var commandText = string.Format("SELECT * FROM
(SELECT max(Revision) as LatestRev
FROM dbo.PDSIsometricSheets)
WHERE Revision < 5" , projectNo);
var commandText = string.Format("SELECT T.IsoShtRevID, T.LineID, T.Filename, T.Revision
FROM dbo.PDSIsometricSheets T
WHERE Revision =
(SELECT MAX(T1.Revision)
FROM dbo.PDSIsometricSheets T1
WHERE T1.IsoShtRevID = T.IsoShtRevID
)", projectNo);
var commandText = string.Format("SELECT IsoShtRevID, LineID, Filename, MAX(Revision) as LatestRevision
FROM dbo.PDSIsometricSheets WHERE SchemaName='{0}'
GROUP BY LineID, IsoShtRevID, Filename", projectNo);
Here are the questions I've visited so far trying to get this to work:
SQL Select only rows with Max Value on a Column
How can I SELECT rows with MAX(Column value), DISTINCT by another column in SQL?
Fetch the row which has the Max value for a column
Select Rows with Maximum Column Value group by Another Column
Everything above either returns the same thing as my original query, or just errors out from bad syntax. SQL is the furthest thing from my forte, and I'm trying to figure out if I'm limited in functionality by using a DataAdapter.
UPDATE:
Here's the latest iteration, using some advice from below:
var commandText = string.Format("SELECT IsoShtRevID, LineID, Filename, MAX(Revision) as MaxRevision " +
"FROM dbo.PDSIsometricSheets " +
"WHERE SchemaName='{0}' AND Revision <= 5 AND Revision >= 0" +
"GROUP BY IsoShtRevID, LineID, Filename", projectNo);
This filters out the revision to values between 0 and 5, however there are still multiple rows for LineID, each with different Revision numbers. It's like the Max command is being ignored...
Option 3 should work but if it doesn't is because FileName or IsoShtRevID change across Revisions. In that case, you can do this:
SELECT a.IsoShtRevID ,
a.LineID ,
a.Filename ,
a.Revision
FROM dbo.PDSIsometricSheets a
join (select max(Revision) as Revision, LineID
from dbo.PDSIsometricSheets where SchemaName ='{0}' ) x
join a on a.Revision = x.Revision and a.LineID=x.LineID
WHERE a.SchemaName = '{0}'
Finally got it thanks to the comments, reading more SQL, and viewing my commandstring diligently at runtime for typos.
var commandText = string.Format("SELECT T1.IsoShtRevID, T1.LineID, T1.FileName, T1.Revision " +
"FROM dbo.PDSIsometricSheets T1 " +
"INNER JOIN (" +
"SELECT LineID, MAX(Revision) as MaxRevision " +
"FROM dbo.PDSIsometricSheets " +
"WHERE SchemaName='{0}' AND Revision <= 5 AND Revision >= 0" +
"GROUP BY LineID" +
") T2 " +
"ON T1.LineID = T2.LineID AND T1.Revision = T2.MaxRevision ", projectNo);

SQL Query to access database

I'm writing a database query that will show me where there is a space for parking. It is only used in July.
There is one table that shows all the spaces and whether they are rented that day. There is another table that has the spaces and their sizes. I want to be able to select those spaces that are available on all the days within the selected time period and have the correct size.
I am having a problem, though, selecting only the spaces available within the given time period. Here is the query so far but it does not contain anything concerning the space size as I want this part to work first.
SELECT C.Plads, SUM[C.optaget] C.[ledlig] FROM
(SELECT Plads FROM OptagetPladser AS A Inner JOIN Bådpladser as B ON
A.plads=B.Pladsnummer
WHERE
(A.dato>=" + Startdato + "and A.dato<="+Slutdato+") //checking the time period
and (a.optaget = 0)) //0 means the space is availible
as C
GROUP BY C.Plads
HAVING SUM(C.optaget) >="+ diffResult+")";//diff result is the timespan
At the moment I'm getting the error
Syntax error (missing operator) in query expression 'SUM[C.optaget]'
Any ideas?
First of all, you should rework your SQL query - it contains too many simple errors.
Here are a few.
Try adding a ',' and make some changes in query:
SELECT C.Plads, SUM(C.optaget), C.ledlig FROM
Your subquery C doesn't have an optaget and ledlig fields too. To fix this add those fields right after sebquery's SELECT
Fix a syntax error here:
(A.dato>=" + Startdato + "and A.dato<="+Slutdato+") which should be:
(A.dato >= " + Startdato + " and A.dato <= "+Slutdato+")
Your last double quote is redundant as well as last ')'. Remove it:
HAVING SUM(C.optaget) >= "+ diffResult+" ;//diff result is the timespan
Below is how your SQL query should look. Please, note: there are still missing fields optaget and ledlig in subquery C.
SELECT C.Plads, SUM(C.optaget), C.ledlig FROM
(
SELECT Plads FROM OptagetPladser AS A
INNER JOIN Bådpladser as B
ON A.plads = B.Pladsnummer
WHERE (A.dato >= " + Startdato + " AND A.dato <= " + Slutdato + ")
AND (a.optaget = 0)
)
AS C
GROUP BY C.Plads
HAVING SUM(C.optaget) >= " + diffResult + ";
I believe, there could appear an architectural or performance issues, but without table data I can't say it for sure.

Eager loading child collections with the help of Future and HQL

I am trying to load the child collection of a child of the entity I am selecting. I am trying to mimic this way of doing it, basically creating two future queries and then enumerating one of them. This should lead to two queries to the database:
var idd = session.CreateQuery("from ItemDeliveryDetail idd " +
"join fetch idd.ItemDelivery " +
"left join fetch idd.SupplierInvoice " +
"where idd.Id = 21931828")
.Future<ItemDeliveryDetail>();
var spc = session.CreateQuery("from SpecialCondition spc " +
"where spc.ItemDelivery " +
"in (select idd.ItemDelivery " +
"from ItemDeliveryDetail idd " +
"where idd.Id = 21931828)")
.Future<SpecialCondition>();
var result = idd.ToList();
The last line indeed results in two queries to the database. The queries are exactly what I expect (They are rather lengthy and I don't think they are relevant to the question, but if you would like to see them, I pasted them here).
Problem is, the results of those two queries are not combined, i.e. the following enumeration will still query the database for the SpecialConditions of each ItemDelivery:
foreach (var itemDeliveryDetail in result)
{
foreach (var specialCondition in itemDeliveryDetail.ItemDelivery
.SpecialConditions)
{
// Do something
}
}
How to fix that?
Your second query does not load the ItemDelivery.SpecialConditions collections; only an unused list of SpecialConditions.
I agree with Rippo in that using batch-size is usually cleaner and more performant, even if it results in one or two more roundtrips.
That said, your second query should be:
var spc = session.CreateQuery("from ItemDelivery id " +
"join fetch id.SpecialCondition "
"where id in (select idd.ItemDelivery " +
"from ItemDeliveryDetail idd " +
"where idd.Id = 21931828)"
.Future<ItemDelivery>();
One quick win might be to add batch-size=50 to the bag mapping between ItemDelivery and SpecialConditions.
However I suggest you read this blog "Eagerly loading entity associations efficiently with NHibernate" post from Ayende as it might provide you with the answer you are looking for.
You are facing the classic select n + 1 problem here. I would rather have 1 or maybe 2 more trips to the database rather than a big cartesian product resultset. I am sure this will be the most performant route.
You need to use the same base query twice which I think is your problem.
var idd = session.CreateQuery("from ItemDeliveryDetail idd " +
"join fetch idd.ItemDelivery " +
"left join fetch idd.SupplierInvoice " +
"where idd.Id = 21931828")
.Future<ItemDeliveryDetail>();
var spc = session.CreateQuery("from ItemDeliveryDetail idd " +
"join fetch idd.ItemDelivery id " +
"join fetch id.SpecialCondition spc " +
"where idd.Id = 21931828")
.Future<ItemDeliveryDetail>();
var result = idd.ToList();
Yes I realise this may cause a cartesian product for you but I have had good success using this technique.

Categories

Resources