How would I write this query with DBIX::Class? - dbix-class

I've seen a few other questions on Stackoverflow that discuss sub-selects, but they usually relate to the use of multiple tables. In most cases, a proper join could serve the same purpose.
However my query below refers to a single table. How would I write this using DBIX::Class?
select ID, username, email, role
from Employees
where (ID in
(select max(ID)
from Employees
where username = 'jsmith'
))
order by ID DESC
Thanks!
--
Edit 1: SQL code fix

The Cookbook has almost the exact same query as example.
Your SQL query doesn't make sense to me because the subquery returns a single id, so WHERE id = () would make more sense.
What are you trying to accomplish with it?

Related

SQL Server : using SELECT in NOT IN WHERE Clause

I've been using this query statement ever since. I wonder why this does not work on SQL Server 2008 R2.
SELECT
UserName
FROM
Users
WHERE
UserName NOT IN (SELECT UserName FROM UserTableT2)
The codes does not return any data. Goal is select all UserName in Users table which do not belong to UserTableT2.
EDIT:
Here's the actual query
Update using #Tim Schelmter's query:
Update :
Update:
Thank you!
I would use NOT EXISTS:
SELECT u.UserName
FROM Users u
WHERE NOT EXISTS
(
SELECT 1 FROM UserTableT2 ut2
WHERE u.UserName = ut2.UserName
)
Why? Because it works also if there are NULL values in UserTableT2.UserName.
Worth reading:
Instead of NOT IN, use a correlated NOT EXISTS for this query pattern.
Always. Other methods may rival it in terms of performance, when all
other variables are the same, but all of the other methods introduce
either performance problems or other challenges.
With your updated columns and tables:
SELECT u.usr_id
FROM ousr u
WHERE NOT EXISTS
(
SELECT 1 FROM ApprovalStageApprovers asa
WHERE u.usr_id = asa.ApprovalUser
)

Can I sort data for an aggregate function?

I have a custom CLR aggregate function. This function concats strings within a group. Now the question is, can I make this function process the data in some specific order or will it always be some random order the DB found suitable? I understand that for most mathematical aggregate functions (MIN, MAX, AVG etc.) it makes no difference in which order the data is processed, but let's say I want to concat strings alphabetically within a group is there something I can do to achieve this result?
Note that it has to be an aggregate function (don't get mislead by the examples below) and that altering the existing CLR function is out of question (all it does is a basic string concat and nothing more).
I tested adding ORDER BY to the SELECT that contains the GROUP BY, but it produced no meaningful results.
SELECT
user.Id, dbo.concat(cat.Name)
FROM
Users user
JOIN Cats cat ON (cat.Owner = user.Id)
GROUP BY user.Id
ORDER BY user.Id, MAX(cat.Name) --kind of meaningless really
I also tried to ORDER BY the table that contains the data which I want to concat before doing a JOIN, but the result was the same.
SELECT
user.Id, dbo.concat(cat.Name)
FROM
Users user
JOIN (SELECT TOP 100 PERCENT /*hack*/ c.* FROM Cats c ORDER BY c.Name) cat ON (cat.Owner = user.Id)
GROUP BY user.Id
Ordering data in a subquery and then doing a GROUP BY didn't work either.
SELECT
t1.Id, dbo.concat(t1.Name)
FROM
(
SELECT TOP 100 PERCENT /*hack*/
user.Id, cat.Name
FROM
Users user
JOIN Cats cat ON (cat.Owner = user.Id)
ORDER BY user.Id, cat.Name
) t1
GROUP BY t1.Id
I was kind of expecting that neither of those will work, but at least now no one can say I haven't tried anything.
P.S. Yes, I have reasons not to use FOR XML PATH. If what I'm asking here cannot be done, I'll live with it.
Based on information from Damien_The_Unbeliever, Vladimir Baranov, Microsoft pages and from few other users (see comments to the question), I can deduce that:
Ordering rows for aggregate function cannot be done directly in the database; However there are hints that this is\might have been a planned feature (see here and here); If MS ever implements this, some existing CLR aggregate functions might start acting weird (as by default those aggregate functions are flagged to be dependent on order)
Ordering has to be implemented directly in the CLR function; It can be a little tricky due to how CLR aggregate functions are being run, but it can be done
Unfortunately I don't have a piece of code to present here, as I didn't had time to alter my CLR function (and doing unordered concat was good enough in my case).
You can include a function in the order by clause.
try it with this dummy date returner:
create function testDate ()
returns datetime
as
begin
declare #returnDate datetime
select #returnDate = CURRENT_TIMESTAMP
return #returnDate
end
run the function with any table (replace SomeTable with a real table) and order by it:
select dbo.testDate (),
*
from SomeTable
order by dbo.testDate () desc
#jahu
EDIT: I thought you wanted to order by a user defined function. Perhaps I am misunderstanding the question. You can order a query by an aggregate function like this:
select CustomerID,
avg(OrderID)
from Orders
group by CustomerID
order by avg(OrderID) desc
The table above has OrderID as a unique column and there can be multiple CustomerID records

Making a query that only shows unique records

I have a table where duplicate entries in one of the columns is possible (emailAddress - some couples share them) and I would like to send email newsletters to them. Is there a way to make a select query where it only shows one copy of the email address if there are multiple?
If you need only emailAddress it is quite simple:
select distinct emailAddress from <YourTableNameHere>
Edited according to request in comments.
If you want to choose both distinct emailAddress and ANY customerName related to it then you must somehow tell SQL how to choose the customerName. The easiest way is to select i.e. MIN(customerName), then all other (usually those that are later in alphabet but it actually depends on collation) are discarded. Query would be:
select emailAddress, min(customerName) as pickedCustomerName
from <YourTableNameHere>
group by emailAddress
You can use the DISTINCT keywprd, or you can GROUP BY.
SELECT DISTINCT email
FROM table
Or
SELECT email, Count(ID)
FROM table
GROUP By email

Using UNION select inside a view

I have a requirement to check if a specific user is already being referenced to one of our transaction tables (we have around 10 transaction tables). I suggested using a VIEW that will contain all the users that are already referenced, then the DEV team could just SELECT through that table to find out if the data they're looking for is there or not,
so here's my query for the view:
SELECT DISTINCT user_ID
FROM transaction_table_1
UNION
SELECT DISTINCT user_ID
FROM transaction_table_2
UNION
SELECT DISTINCT user_ID
FROM transaction_table_3
UNION
SELECT DISTINCT user_ID
FROM transaction_table_4
[...]
Right now it works, but my question is, is this a good idea? The requirement asks that I only provide a script (or a view) and not a stored procedure, I think this would be better with an SP since I could just do a quick IF EXIST() statement for each of the table and just check if the parameter user exists in any of the table, but they really wanted it to be only a script they could check (and no using of variables).
Can you guys give me advice on a better way of doing this requirement, that would have less impact on performance since this may not be the optimized solution for this requirement.
TIA,
Rommel
Well, you can remove the DISTINCT because UNION already makes it :)
SELECT user_ID
FROM transaction_table_1
UNION
SELECT user_ID
FROM transaction_table_2
UNION
SELECT user_ID
FROM transaction_table_3
UNION
SELECT user_ID
FROM transaction_table_4
But since you have to use a view, I don't see how to make it differently.
From a performance point of view I would structure the query slightly differently:
SELECT DISTINCT user_ID
FROM (
SELECT user_ID
FROM transaction_table_1
UNION ALL
SELECT user_ID
FROM transaction_table_2
UNION ALL
SELECT user_ID
FROM transaction_table_3
...
) x
This will reduce the number of unique index scans that need to be done to 1 - rather than having one each time a UNION is performed

How to elegantly write a SQL ORDER BY (which is invalid in inline query) but required for aggregate GROUP BY?

I have a simple query that runs in SQL 2008 and uses a custom CLR aggregate function, dbo.string_concat which aggregates a collection of strings.
I require the comments ordered sequentially hence the ORDER BY requirement.
The query I have has an awful TOP statement in it to allow ORDER BY to work for the aggregate function otherwise the comments will be in no particular order when they are concatenated by the function.
Here's the current query:
SELECT ID, dbo.string_concat(Comment)
FROM (
SELECT TOP 10000000000000 ID, Comment, CommentDate
FROM Comments
ORDER BY ID, CommentDate DESC
) x
GROUP BY ID
Is there a more elegant way to rewrite this statement?
So... what you want is comments concatenated in order of ID then CommentDate of the most recent comment?
Couldn't you just do
SELECT ID, dbo.string_concat(Comment)
FROM Comments
GROUP BY ID
ORDER BY ID, MAX(CommentDate) DESC
Edit: Misunderstood your objective. Best I can come up with is that you could clean up your query a fair bit by making it SELECT TOP 100 PERCENT, it's still using a top but at least it gets around having an arbitrary number as the limit.
Since you're using sql server 2008, you can use a Common Table Expression:
WITH cte_ordered (ID, Comment, CommentDate)
AS
(
SELECT ID, Comment, CommentDate
FROM Comments
ORDER BY ID, CommentDate DESC
)
SELECT ID, dbo.string_concat(Comment)
FROM cte_ordered
GROUP BY ID

Resources