MySql SelecT CASE WHEN THEN SELECT - case

i have a problem, if anyone could help me, problem " Subquery returns more than 1 row "
I need to select the drivers for the dropdown field,
if driving for Van then selects only Van drivers
if driving for Kombi then selects Kombi and Van drivers
if driving for Limo then selects all drivers
SELECT CASE
WHEN "Van"="Van"
THEN (SELECT fahrername FROM fahrer WHERE auto = 'Van')
WHEN "Kombi"="Kombi"
THEN (SELECT fahrername FROM fahrer WHERE auto = 'Kombi' AND auto = 'Van')
ELSE (SELECT fahrername FROM fahrer)
END
SOLVED:
I solved the problem in another way
thanks anyway
I added to the car driver new value
an Limo - value Limo
an Kombi - value LimoKombi
and Van - value LimoKombiVan
and I solved using LIKE
SELECT
fahrername
FROM
fahrer
WHERE
auto LIKE '%{typauto}%'
I think it's easier this way...
thank you anyway

If you want to use user-defined variables
set #vehType='Van';
select fahrername from fahrer where #vehType = 'Limo'
union select fahrername from fahrer where #vehType = 'Kombi' and auto in ('Kombi','Van')
union select fahrername from fahrer where #vehType = 'Van' and auto = 'Van';

Related

EF Core - Count from a specific column

I almost have my EF Core query working... This is the SQL getting produced (notice the Count(*):
SELECT [u].[Key], [u].[Url], [u].[CreatedBy], [u].[CreatedOn], COUNT(*) AS [Clicks]
FROM [URLs] AS [u]
LEFT JOIN [OwnerUrls] AS [o] ON [u].[Key] = [o].[ShortUrlKey]
LEFT JOIN [Clicks] AS [c] ON [u].[Key] = [c].[ShortUrlKey]
GROUP BY [u].[Key], [u].[Url], [u].[CreatedBy], [u].[CreatedOn]
What I need is (have Count look at a specific column/table)
SELECT [u].[Key], [u].[Url], [u].[CreatedBy], [u].[CreatedOn], COUNT(c.ID) AS [Clicks]
FROM [URLs] AS [u]
LEFT JOIN [OwnerUrls] AS [o] ON [u].[Key] = [o].[ShortUrlKey]
LEFT JOIN [Clicks] AS [c] ON [u].[Key] = [c].[ShortUrlKey]
GROUP BY [u].[Key], [u].[Url], [u].[CreatedBy], [u].[CreatedOn]
Here is the EF Query that I'm using...
query = (from u in db.URLs
join ou in db.OwnerUrls on u.Key equals ou.ShortUrlKey into urlOwners
from subSet in urlOwners.DefaultIfEmpty()
join c in db.Clicks on u.Key equals c.ShortUrlKey into urlClicks
from subClicks in urlClicks.DefaultIfEmpty()
group subClicks by new { u.Key, u.Url, u.CreatedBy, u.CreatedOn } into g
select new ShortURL()
{
Key = g.Key.Key,
Url = g.Key.Url,
CreatedBy = g.Key.CreatedBy,
CreatedOn = g.Key.CreatedOn,
Clicks = g.Count()
});
I've tried changing the g.Count() to g.Select(x=>x.Id).Count() and that just causes EF Core to barf and complain about client side evaluation vs server side evaluation etc..
I should mention that the reason I'm joining the first model (OwnerUrls) is to support a where clause that I didn't include here...
Thanks!
I'm not a EF developer, but have worked with SQL Server for a while now. In SQL Server i would use COUNT(DISTINCT c.ID) to eliminate any duplicates you might get from JOINS.
If duplicates are impossible due to the model the COUNT(*) shoud be sufficient.
Maybe this might help:
https://entityframeworkcore.com/knowledge-base/51892585/linq-select-distinct-count-performed-in-memory

Insert an AVG() Value from a table into the same table

I have one table named Test with columns named ID,Name,UserValue,AverageValue
ID,Name,UserValue,AverageValue (As Appears on Table)
1,a,10,NULL
2,a,20,NULL
3,b,5,NULL
4,b,10,NULL
5,c,25,NULL
I know how to average the numbers via (SELECT Name, AVG(UserValue) FROM Test GROUP BY Name)
Giving me:
Name,Column1(AVG(Query)) (As Appears on GridView1 via databind when I run the website)
a,15
b,7.5
c,25
What I need to do is make the table appear as such by inserting the calculated AVG() into the AverageValue column server side:
ID,Name,UserValue,AverageValue (As Appears on Table)
1,a,10,15
2,a,20,15
3,b,5,7.5
4,b,10,7.5
5,c,25,25
Conditions:
The AVG(UserValue) must be inserted into Test table AverageValue.
If new entries are made the AverageValue would be updated to match AVG(UserValue).
So what I am looking for is a SQL command that is something like this:
INSERT INTO Test (AverageValue) VALUES (SELECT Name, AVG(UserValue) FROM Test GROUP BY Name)
I have spent considerable amount of time searching on google to find an example but have had no such luck. Any examples would be greatly appreciated. Many thanks in advance.
Try this:
with toupdate as (
select t.*, avg(uservalue) over (partition by name) as newavg
from test t
)
update toupdate
set AverageValue = newavg;
The CTE toupdate is an updatable CTE, so you can just use it in an update statement as if it were a table.
I believe this will do the trick for you. I use the merge statement a lot! It's perfect for doing things like this.
Peace,
Katherine
use [test_01];
go
if object_id (N'tempdb..##test', N'U') is not null
drop table ##test;
go
create table ##test (
[id] [int] identity(1, 1) not null,
[name] [nvarchar](max) not null,
[user_value] [int] not null,
[average_value] [decimal](5, 2),
constraint [pk_test_id] primary key([id])
);
go
insert into ##test
([name], [user_value])
values (N'a',10),
(N'a',20),
(N'b',5),
(N'b',10),
(N'c',25);
go
with [average_builder] as (select [name],
avg(cast([user_value] as [decimal](5, 2))) as [average_value]
from ##test
group by [name])
merge into ##test as target
using [average_builder] as source
on target.[name] = source.[name]
when matched then
update set target.[average_value] = source.[average_value];
go
select [id], [name], [user_value], [average_value] from ##test;
go

How to select latest Row from table without using ORDER BY

How can I select latest row from by table without sorting it?
It is because it follow by the ID AUTO INCREMENT...
I'm using c# asp.net to select... I did try using LIMIT 5 but it give me an error page..
rSQL = "select COUNT(*) from chatLog_db where sessionid='" + grpID + "' LIMIT 5";
Is there any better way to solve this matter?
I'd appreciate any help please.
You have an id column which is autoincremented, right? Then you can do it like this..
select * from tablename where id=(select MAX(rid) from tablename)
On MSSQL simply use the top 1 instead of limit
select top(1) * from mytable order by some_column
http://msdn.microsoft.com/en-us/library/ms189463.aspx
if the latest means the max id
select * from chatLog_db
where id = (select max(id) from chatLog_db);
EDIT
select 5 records
select * from chatLog_db
where id > (select max(id) - 5 from chatLog_db);
You can try
SELECT * FROM chatLog_db WHERE sessionid > (SELECT MAX(sessionid) - 1 FROM chatLog_db);
You may also try for
SELECT * FROM chatLog_db WHERE sessionid > (SELECT MAX(sessionid) - 5 FROM chatLog_db);
You may use max as well like
select * from chatLog_db where sessionid = (select max(sessionid) from chatLog_db);
Something like that.
If you are not using order by into your query because you are thinking that it will change the order of your dsplay data then i will tell you that there is one trick as well to sort your data as per your need
you can also sort your data as per your need even if you are using
order by into your query,put the result into DataView and sort it
according to your need because DataView allow us sorting facility as
well.
Latest by using Order By like
select * from tablename order by columnname desc LIMIT 5;
Hope it works for you.

SELECT MAX() contained within a DATEDIFF()

I am writing a report for the desktop support team in the company where I work. The report needs to produce a set of new starters within a specified time frame passed in from an ASP.NET application. Currently there is a one to many relationship between our Worker table and Contract table. We hire a lot of contractors and they sometimes come back after a number of months but are still treated like new starters as new machines need to be configured along with desk space.
A new contract is added for every pay review, job title change and new starter. We need to filter out all but the new starter. The newest contract that is added for job changes and pay reviews is always one day after the end date of the previous contract naturally. As I am only still a fresher in the grand scheme of things I am struggling with a set of functions I am trying to use to achieve my goal.
WHERE
(dbo.[Contract].StartDate BETWEEN #StartDateF AND #EndDateF) AND DATEDIFF(day, SELECT MAX(StartDate)FROM dbo.[Contract] WHERE dbo.[Contract].Worker_ID = w1.Worker_ID, SELECT MAX(EndDate)FROM dbo.[Contract] WHERE dbo.[Contract].Worker_ID = w1.Worker_ID)> 1
I basically want to find out in the instance an employee has more than one contract, regardless of leaving and coming back or pay review, if the current active contract is one day different to the previous contract. This should by my thinking give me all new starters only.
Trouble is I am still trying to get my head around when to use aggregate functions not in a select and when to apply the HAVING clause.
Any help would be appreciated to help me understand why my lack of understanding is causing this query/logic to fail.
Thanks
EDIT
Ok I am still bashing away at this solution and this is syntactically incorrect. In an attempt to remove some of the ambiguity here is the query, with an update;
Declare #StartDateF varchar(10)
Set #StartDateF = '2012-08-03'
Declare #EndDateF varchar(10)
Set #EndDateF = '2012-09-04'
SELECT w1.Worker_ID, w1.Title, w1.FirstName, w1.Surname,w1.Gender, w1.DateofBirth,
dbo.[Contract].StartDate, (select w2.surname + ',' + w2.firstname from worker w2 WITH (NOLOCK) where w2.worker_ID = w1.manager)as Manager, dbo.Grade.GradeDescription AS JobTitle, dbo.Grade.Discipline,
CASE WHEN dbo.[Contract].ContractType_ID = 1 OR dbo.[Contract].ContractType_ID = 2 OR dbo.[Contract].ContractType_ID = 5 OR dbo.[Contract].ContractType_ID = 6
THEN 'Staff' ELSE 'Contractor' END AS ContractType
FROM dbo.Worker w1 WITH (NOLOCK) inner join
dbo.[Contract] WITH (NOLOCK) ON dbo.[Contract].Worker_ID = w1.Worker_ID inner join
dbo.Grade WITH (NOLOCK) ON dbo.Grade.Grade_ID = dbo.[Contract].Grade_ID
WHERE
(dbo.[Contract].StartDate BETWEEN #StartDateF AND #EndDateF AND EndDate IS NULL)
group by
w1.Worker_ID, w1.Title, w1.FirstName, w1.Surname,w1.Gender, w1.DateofBirth,
dbo.[Contract].StartDate, manager, dbo.Grade.Discipline,dbo.Grade.GradeDescription, dbo.[Contract].ContractType_ID
Having DATEDIFF(day, SELECT MAX(StartDate)FROM dbo.[Contract] WHERE dbo.[Contract].Worker_ID = w1.Worker_ID, SELECT MAX(EndDate)FROM dbo.[Contract] WHERE dbo.[Contract].Worker_ID = w1.Worker_ID)
I have added the group by and the having clause but now I am getting the following errors
Msg 156, Level 15, State 1, Line 24
Incorrect syntax near the keyword 'SELECT'.
Msg 102, Level 15, State 1, Line 24
Incorrect syntax near ','.
Msg 102, Level 15, State 1, Line 24
Incorrect syntax near ')'.
These all relate the the functions in the having clause no doubt you can see. But I cannot understand what is wrong with this query and this is mainly the question. I need to understand the SQL functions enough so that I can implement th correct solution.
I have followed up the DATEDIFF() function here http://msdn.microsoft.com/en-us/library/ms189794.aspx
I can see that using functions within this function is acceptable according to the MS documentation.
EDIT
Commenting out the Having clause gives me the result set I expect. It is showing people with changes to contracts(pay rise) but this is information that no one should be seeing, these are now the only records that need filtering out
EDIT
I have made some improvements and overcome the error messages now, but I am still getting people where pay rises have occured. Here is the amended query from the group by
group by
w1.Worker_ID, w1.Title, w1.FirstName, w1.Surname,w1.Gender, w1.DateofBirth,
dbo.[Contract].StartDate, manager, dbo.Grade.Discipline,dbo.Grade.GradeDescription, dbo.[Contract].ContractType_ID, w1.Worker_ID
Having
(((dbo.[Contract].StartDate BETWEEN #StartDateF AND #EndDateF)
AND COUNT(dbo.[Contract].Worker_ID) = 1)
OR
((dbo.[Contract].StartDate BETWEEN #StartDateF AND #EndDateF)
AND DATEDIFF(day, (SELECT MAX(EndDate)FROM dbo.[Contract] WHERE dbo.[Contract].Worker_ID = w1.Worker_ID), (SELECT MAX(StartDate)FROM dbo.[Contract] WHERE dbo.[Contract].Worker_ID = w1.Worker_ID))>1))
To get workers with more than one contract, you would use:
select c.workerID
from Contract c
group by c.workerID
having count(distinct contractID) > 1
It sounds, though, like you only want to count everything but the new start ones. You can do this with something like:
select w.workerID
from Contract c
where c.ContractType = 'New'
group by w.workerID
having count(distinct contractID) > 1
Because you didn't provide the details of what the tables look like, what sample input data looks like, and the results you want to achieve, this is about the best that can be done.
WHERE ( (dbo.[Contract].StartDate BETWEEN #StartDateF AND #EndDateF)AND dbo.[Contract].Worker_ID
IN (select worker_id from dbo.[Contract]
group by worker_id
having count(worker_id) = 1))
OR
((dbo.[Contract].StartDate BETWEEN #StartDateF AND #EndDateF)
AND DATEDIFF(day, (SELECT MAX(EndDate)FROM dbo.[Contract] WHERE dbo.[Contract].Worker_ID = w1.Worker_ID), (SELECT MAX(StartDate)FROM dbo.[Contract] WHERE dbo.[Contract].Worker_ID = w1.Worker_ID))>1
AND dbo.[Contract].Worker_ID = w1.Worker_ID )
Now works for me :)

How do I make an UPDATE while joining tables on SQLite?

I tried :
UPDATE closure JOIN item ON ( item_id = id )
SET checked = 0
WHERE ancestor_id = 1
And:
UPDATE closure, item
SET checked = 0
WHERE ancestor_id = 1 AND item_id = id
Both works with MySQL, but those give me a syntax error in SQLite.
How can I make this UPDATE / JOIN works with SQLite version 3.5.9 ?
You can't. SQLite doesn't support JOINs in UPDATE statements.
But, you can probably do this with a subquery instead:
UPDATE closure SET checked = 0
WHERE item_id IN (SELECT id FROM item WHERE ancestor_id = 1);
Or something like that; it's not clear exactly what your schema is.
You can also use REPLACE then you can use selection with joins.
Like this:
REPLACE INTO closure
SELECT sel.col1,sel.col2,....,sel.checked --checked should correspond to column that you want to change
FROM (
SELECT *,0 as checked FROM closure LEFT JOIN item ON (item_id = id)
WHERE ancestor_id = 1) sel

Resources