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.
Related
Developing an application in C# using a MySQL database. It involves cows and their weights. When displaying the cows details in a table, I want to display all of the animal's details as well as their last weight.
I have two tables used for this: 'Cattle' and 'Weights'. Each animal has a unique ID and this ID is used as foreign key in weights table along with the date taken and what they weighed. Up to now the way I am doing it is getting the MAX(Date) in the weights table and using a left join however if animal wasn't weighed on that date then it won't be included. I could use each animals MAX(Weight) however some animals may drop in weight due to illness etc.
SELECT Cattle.TagNumber,
Cattle.HerdNumber,
Cattle.Breed,
Cattle.DOB,
Cattle.Group,
Weights.Weight
FROM Cattle
LEFT JOIN Weights ON Cattle.TagNumber = Weights.TagNumber
WHERE Cattle.Group = '" + group + "'
AND Date = '" + date.ToString("yyyy/MM/dd") + "'";
The above query is what I use when filtering the data by the animals group. I understand that I could go through each animal individually and get their MAX(Weight) however this severely hinders the performance.
If you select for the Max(Date) found on the join, instead of searching a specific Date (Where clause), you will always get the results. Not exactly sure if this is what is asked.
SELECT Cattle.TagNumber,
Cattle.HerdNumber,
Cattle.Breed,
Cattle.DOB,
Cattle.Group,
Weights.Weight,
MAX(Date)
FROM Cattle
LEFT JOIN Weights ON Cattle.TagNumber = Weights.TagNumber
WHERE Cattle.Group = '" + group + "'
Group by Cattle.TagNumber;
Edit
The query should also return values with no weights; you just need to filter the data. You can use Case (it might not work exactly as I wrote it, but something around that). There was the End missing; also you probably need to convert weight to a nvarchar (or what you chose), otherwise you will get an error when inserting weight in the column NAMECOLUMN
SELECT Cattle.TagNumber,
Cattle.HerdNumber,
Cattle.Breed,
Cattle.DOB,
Cattle.Group,
(Case when Weights.Weight is null then 'N/A' Else Convert(nvarchar(max),Weights.Weight) End) as NAMECOLUMN,
MAX(Date)
FROM Cattle
LEFT JOIN Weights ON Cattle.TagNumber = Weights.TagNumber
WHERE Cattle.Group = '" + group + "'
Group by Cattle.TagNumber;
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
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.
I am trying to parse through hundreds of stored procedures to specifically grab their output variables "#FirstName", which tables they use, and which fields they pull from "MyTbl.FirstName". I am able to collect the variables pretty easily but I'm having trouble collecting the table names. Could anyone help?
So far I've been able to pull most of these fields by parsing through the SQL files using the StreamReader and collecting information line by line, for example if a line contains output, then I know the first text in the line is most likely the #Variable.
#Address1 varchar(45) output,
#Address2 varchar(45) output,
#City varchar(35) output,
#State varchar(2) output,
#Zip varchar(10) output
From there I can store the #Variable into a dictionary and if any line contains the #Variable and also contains a '=' then I know we have a match as to which field it corresponds to.
#Address1 = c.Address,
#Address2 = c.AddressSecondLine,
#City = c.City,
#State = c.State,
#Zip = c.ZipOrPostalCode
Now I'm just having issues gathering the table name. I can easily parse the table alias off the field name but I'm having issues matching the alias with a table name. Does anyone know of a good way to do this? Here's what I've been trying so far:
FROM Table.dbo.SalesStuff ss
LEFT OUTER JOIN Table.dbo.Customer c ON ss.CustNo = c.CustNo
Left JOIN Table.dbo.Vending v on #tmpVin = v.vin
Code:
keyColl = tables.Keys;
foreach (string var in keyColl)
{
if (line.Contains(" " + var + '\r') || line.Contains(" " + var + " ") || line.Contains(" " + var + ((char)13)) || line.Contains(" " + var + Environment.NewLine))
{
tables[var] = line.ToString();
break;
}
}
I thought that this would match the table alias since most aliases are a letter, followed by a line break, but so far I haven't been able to get any of the table names... Does anyone have an idea?
Quite frankly I don't think you're going to get very far with your parsing idea. You're making very brave assumptions about how code is going to be formatted in every single procedure. I'm very meticulous about formatting but there's no way I could guarantee the kind of consistency you're depending on across that many procedures, even if I did write them all myself.
With the caveat that deferred name resolution can bite you in the rear and that dependency tracking was certainly far from perfect in SQL Server 2005 (see the workarounds I posted for keeping it accurate even in SQL Server 2008), here are a couple of ideas (and they're not perfect either, but they'll definitely cause less gray hair):
You can get parameters in a much easier way than brute force parsing, by using the catalog view sys.parameters:
SELECT OBJECT_NAME([object_id]), p.name, t.name
FROM sys.parameters AS p
INNER JOIN sys.types AS t
ON p.system_type_id = t.system_type_id
WHERE p.is_output = 1;
If all of your procedures have been recompiled and you are not subject to deferred name resolution issues, you can get table names and column names from sys.sql_dependencies - however this will include columns that are referenced in where/join clauses even if they are not in the select list:
SELECT [procedure] = OBJECT_NAME(d.[object_id]),
[table] = OBJECT_NAME(d.referenced_major_id),
[column] = c.name
FROM sys.sql_dependencies AS d
INNER JOIN sys.columns AS c
ON c.[object_id] = d.referenced_major_id
AND c.column_id = d.referenced_minor_id;
There is a column here called is_selected but I have not found it to be accurate/reliable.
Note that anything that happens in dynamic SQL stays in dynamic SQL - so if your procedures use dynamic SQL it will be next to impossible to cull out table/column names.
you can use regular expressions. For example for string like
FROM Table.dbo.SalesStuff ss
you can use
string pattern = #"\s*FROM\s+Table\.dbo\.(\w+)\s+(\w+)";
string input = "line from stored proc body here";
MatchCollection matches = Regex.Matches(input, pattern);
foreach (Match match in matches)
{
Console.WriteLine("table name: {0}", match.Groups[1].Value);
Console.WriteLine("Alias: {0}", match.Groups[2].Value);
Console.WriteLine();
}
you must define pattern for each type of string containing table name and alias.
string sqlQueryString = " SELECT g.code AS GoodCode, g.name AS GoodName, " +
"msr.name AS MsrName, sm.min_quan AS KolMin, sm.max_quan AS KolMax, " +
"sm.quan AS KolNal, ord.prc AS EdPrice, s.name AS Sklad, m.name AS Mol, " +
"k.code AS KodDost, k.name AS NameDost " +
"FROM N_GOODS_{0} AS g INNER JOIN " +
"G_SMGS_{0} AS sm ON g.id = sm.good_id INNER JOIN " +
"N_KNTRS_{0} AS k ON g.id = k.id INNER JOIN " +
"N_PRC_LISTS_{0} AS pr ON g.id = pr.id INNER JOIN " +
"G_ORDD_{0} AS ord ON sm.smg_id = ord.smg_id INNER JOIN " +
"N_MOLS_{0} AS m ON sm.mol_id = m.id INNER JOIN " +
"N_STORS_{0} AS s ON sm.stor_id = s.id INNER JOIN " +
"N_MSRS_{0} AS msr ON g.id = m.id";
sqlQueryString = String.Format(sqlQueryString, dbLink.CurrentFirm.Id);
return " ( " + sqlQueryString + " ) AS t";
This is the string for an sql query, that I am trying to do in a piece of c# code. However I lost my whole day trying to make it work. This is the error that I get :
Incorrect syntax near the keyword 'FROM'.
Incorrect syntax near the keyword 'AS'.
Try:
return "SELECT * FROM ( " + sqlQueryString + " ) AS t";
Additionally you should try setting a breakpoint on your return statement. Get the value of sqlQueryString there and try running it directly in SQL Server Management Studio.
First, this probably isn't a C# question except to say that you should likely learn the...
string strSql = #"SELECT *
FROM TABLE";
syntax so that 1.) You can do away with all the " + stuff and 2.) You can cut and paste something in from an isql client.
So what you really want to do is...
Debug in your IDE by setting a breakpoint at that last line,
Hover your cursor over sqlQueryString,
Right-click sqlQueryString in the "floater" that appears (I put my mouse over strReturn, the floater comes up. Right click the strReturn that appears floating above -- blue rectangle is what you want)
Select the option to copy the value.
Paste your clipboard with sqlQueryString's contents into Notepad, gvim, whatever.
Let us know what that says.
Then tell us precisely what happens when you run that statement directly against the database.
You might also give us some idea of what you expected to happen [based on having run the original query against the database earlier, perhaps].
And then accept that even the best of us occasionally lose an hour or two doing something dumb with SQL. ;^) With the above information, however, we could probably help cut that down a bit.
EDIT: Rather, if, as your comment suggests, the query works when run directly against (MS-SQL Server?), the C# issue potentially comes after this code, when you run it against the database. First do the above and ensure what's in sqlQueryString is what you ran against the db.
EDIT2: Made the debug steps into a bulleted list to make them more obvious. Don't just tell us it work; tell us what was in sqlQueryString. But, again, as with the first edit, if that string is okay, your problem likely occurs later on in your C# code.
Are you immediately throwing against the database? What's that code look like?
Looks like the problem is in the return statement at the end.
( SELECT foo FROM bar ) AS baz; is not a valid SQL statement by itself, it's a fragment.
As #Yuck suggests, try SELECT * FROM ( " + sqlQueryString + " ) AS t"; instead.