SELECT *
FROM dbo.vwAlarmAssetGroupLocationReport
WHERE (LocationID = CAST(COALESCE(#LocationId, LocationId) AS UNIQUEIDENTIFIER)
OR TopLocationId = CAST(COALESCE(#LocationId, TopLocationId) AS UNIQUEIDENTIFIER))
AND DateCreated BETWEEN '2018-10-23 AND 2018-10-25'
AND AssetGroupId = '8E99BAFB-739A-E411-B54B-40F2E9985B7A'
ORDER BY DateCreated
keep getting this error message when I try to run my report in SQL Any ideas?
The problem is you have to define LocationId first.
Try add in front of your codeblock:
DECLARE #LocationID DATATYPE
SET #LOCATION ID = VALUE
You need to have a declaration for #locationID before running the main query like:
declare #LocationId int = 10;
SELECT * FROM dbo.vwAlarmAssetGroupLocationReport
WHERE (LocationID = CAST(COALESCE(#LocationId, LocationId) AS uniqueidentifier) OR TopLocationId = CAST(COALESCE(#LocationId, TopLocationId) AS uniqueidentifier))
AND DateCreated Between '2018-10-23' AND '2018-10-25'
AND AssetGroupId = '8E99BAFB-739A-E411-B54B-40F2E9985B7A'
ORDER BY DateCreated
ALso please notice that the AND keyword after BETWEEN keyword should not be in the quotes.
Related
I have a simple query that I am trying to adapt to a new situation. For this situation, if the variable locationID=1 then I need all records, regardless of its locationID.
However, if it is not equal to 1, I need to only provide records that match that of the #locationID.
Here is my setup example:
DECLARE #locationID INT = 1; -- All Results Regardless of locationID
--DECLARE #locationID INT = 2; -- Only results that match this locationID (2)
--DECLARE #locationID INT = 3; -- Only results that match this locationID (3)
-- Temp Data
DECLARE #temp AS TABLE (color VARCHAR(10), locationID INT, name VARCHAR(20))
INSERT INTO #temp( color, locationID, name )VALUES ( 'Blue', 1, 'Test 1' )
INSERT INTO #temp( color, locationID, name ) VALUES ( 'Red', 2, 'Test 2' )
INSERT INTO #temp( color, locationID, name ) VALUES ( 'Red', 1, 'Test 3' )
INSERT INTO #temp( color, locationID, name ) VALUES ( 'Red', 2, 'Test 4' )
INSERT INTO #temp( color, locationID, name ) VALUES ( 'Red', 3, 'Test 5' )
-- Query
SELECT *
FROM #temp
WHERE
locationID = ...
I am trying to figure out if I need to use a CASE WHEN or some other method for this.
WHERE (locationID = #LocationId OR #locationID = 1)
Try this:
...WHERE (#LocationId = 1 AND 1=1)
OR (#LocationId <> 1 AND LocationId = #LocationId)
This seems devilishly simple, perhaps I am not understanding your question. If you want to query by a variable value, then just use the variable value:
DECLARE #LocationId INT = 1
SELECT *
FROM #temp
WHERE (#LocationId = 1 AND 1=1)
OR (#LocationId <> 1 AND LocationId = #LocationId)
A couple of other ideas. Since using a constant of 1 is not exactly intuitive or self-documenting, you could default that to NULL. And then say:
WHERE LocationID = COALESCE(#LocationID, LocationID);
If LocationID column is nullable, then instead you could use some token value that is at least slightly more self-documenting than 1, like -1 (since I don't think anyone looking at the code will immediately know that there isn't really a valid row where LocationID = 1):
WHERE LocationID = COALESCE(NULLIF(#LocationID, -1), LocationID);
This is susceptible to parameter sniffing, so you might want to add OPTION (RECOMPILE) if you find you are often switching between "all rows" and "very specific rows." You can also use dynamic SQL to optionally build the WHERE clause, assuming your real scenario uses a real table:
DECLARE #sql nvarchar(max) = N'SELECT ... FROM dbo.RealTable'
IF #LocationID <> 1 -- or IS NOT NULL or <> -1 or what have you
BEGIN
SET #sql += N' WHERE LocationID = #LocationID';
END
EXEC sys.sp_executesql #sql, N'#LocationID int', #LocationID;
This way you get a different plan when the parameter is included vs. when it is not, which doesn't really make the scan (where you need all rows) any better, but it guards against the case where you use a seek + lookup against all rows, which can be really bad. More often, it prevents you from getting the dreadful full table/index scan when you really could have used a seek. But which way that goes is completely dependent on which case is more likely the first time the query runs.
And even here you may want to use OPTION (RECOMPILE) at the end of #sql if the distribution of data across different LocationID values is (or might later become) heavily skewed.
I call this type of query "the kitchen sink," and have written about it here:
#BackToBasics : An Updated "Kitchen Sink" Example
So the variable should be 1 or the locationid?
You could use an IN for that.
... WHERE #LocationID IN (1, LocationID)
Example snippet:
declare #locationID int;
-- Test data using a table variable
declare #varTable table (id int identity(1,1) primary key, locationID int, name varchar(20), color varchar(10));
insert into #varTable (locationID, name, color) values
(1,'Test 1','Blue'),
(2,'Test 2','Red'),
(1,'Test 3','Red'),
(2,'Test 4','Red'),
(3,'Test 5','Red');
-- Returning all records
set #locationID = 1;
SELECT t.* FROM #varTable t WHERE #locationID IN (1, t.locationID);
-- Only returning those with locationID = 2
set #locationID = 2;
SELECT t.* FROM #varTable t WHERE #locationID IN (1, t.locationID);
I want to save data in a variable and use it later in a procedure.
UPDATE acc_Account
SET acc_Account.CompanyID = ( SELECT TOP 1
utl_Company.CompanyID
FROM utl_Company
ORDER BY CompanyID DESC
)
WHERE acc_Account.AccountNumber = #AccountNumber
how can I save the CompanyID in a variable to use it in an insert statement later on?
Have this in the beginning of your code:
declare #var varchar(20) -- change the data type according to your needs
set #var = (SELECT TOP 1 utl_Company.CompanyID FROM utl_Company ORDER BY CompanyID DESC)
Create a select local variable before the update statement, then set it, then use it.
DECLARE #companyID INT;
SELECT #companyID = "YOUR QUERY";
I think the efficient way would be using OUTPUT clause
DECLARE #TAB TABLE (CompanyID BIGINT )
UPDATE acc_Account
SET acc_Account.CompanyID = (
SELECT max(CompanyID) FROM utl_Company
)
output inserted.CompanyID into #TAB
WHERE acc_Account.AccountNumber = #AccountNumber
SELECT * FROM #TAB
I have to write a query for a login page where the user can enter either emailid(varchar datatype) or userid(int datatype). How do I write a query for this without knowing the datatype of the input?
CREATE PROCEDURE my_stored_procedure
#emailId nvarchar(50) = NULL,
#userId int = NULL
AS
SET NOCOUNT ON;
IF (#emailId IS NOT NULL) AND (LEN(#emailId) > 0)
SELECT * FROM MYTABLE WHERE EmailId = #emailId
ELSE
SELECT * FROM MYTABLE WHERE UserId = #UserId
GO
Your input parameter should be of varchar type.
Then in your procedure use ISNUMERIC function to check for number. Have two queries based on that with IF statement in case if it is int or varchar.
DECLARE #userInput VARCHAR(50)
IF ISNUMERIC(#userInput) = 1
BEGIN
-- Your query with userid
END
ELSE
BEGIN
-- Your query with emailid
END
Try this query it may help you.
DECLARE #emailid varchar(250),#userid bigint
set #emailid='A'
SET #userid=3
select * from yourtable
where case when #emailid='A' THEN 'A' ELSE emailid END=#emailid
AND case when #userid=0 THEN 0 ELSE userid END=#userid
Note: You should pass 'A' as default value for email_id and 0 for userid or else you can pass your required input
I have a table 'Asset' in database. This table has four fields (Id, Name, LocationId, CategoryId).
I want to make a stored procedure which will return the assets based on provided LocationId and CategoryId parameters.
I want to make Where clause optional with respect to LocationId i.e. If user passes LocationId as 0 then I dont want to put restriction on LocationId otherwise I need to put restriction on LocationId also. i.e If #LocationId is 0 then assets from all location ids should be returned.
How can I change following query to achieve this
select * from Asset where LocationId = #LocationId and CategoryId = #CategoryId
Any Help?
What you need to do is declare your variables as null at the beginning.
So #LocationID int = null
Then in your where clause you'll want to put something like
WHERE (LocationID = #LocationID or #LocationID IS NULL)
That way if you don't pass an ID, everything will be returned.
EDIT - So this works for you, just make the passing of the ID's optional instead of putting 0's in, you could of course do WHERE (LocationID = #LocationID or #LocationID = 0)
I just think the use of NULL's is much cleaner.
Full Query:
CREATE PROC
#LocationID int = 0,
#CategoryID int = 0
AS
SELECT *
FROM
Asset
WHERE
(LocationID = #LocationID or #LocationID = 0)
AND
(ActivityID = #ActivityID or #ActivtyID = 0)
You can use Case in your Where Clause
select * from Asset
where LocationId = Case When #LocationId=0 then LocationId else #LocationId end
and CategoryId = #CategoryId
This was resolved. The statement was in another part of the stored procedure.
The stored procedure I'm writing won't allow me to do this:
declare #dtTopDate datetime
select top 1 #dtTopDate = date_build
from database..table
where database..table.parent = #Parent
and database..table.child = #Child
order by date_build desc
Gives me this error:
Column "database..table.date_build" is
invalid in the ORDER BY clause because
it is not contained in either an
aggregate function or the GROUP BY
clause.
What am I doing wrong?
[Edit] There is no group by statement here. SQL2005.
Here is some more context:
if #Notify = 0
begin
declare #dtTopDate datetime
select top 1 #dtTopDate = date_build
from database..table
where database..table.parent = #Parent
and database..table.child = #Child
order by date_build desc
insert
into database2..table
(parent, child, notification_date, change_date)
values (#Parent, #Child, #dtTopDate, getdate())
return
end
This works for me, but I'm not sure if this is what you are trying to do b/c your example has some errors.
use Test
go
CREATE TABLE [dbo].[MyTable]
(
[MyTableId] [uniqueidentifier] NOT NULL,
[MyDate] [datetime] NOT NULL,
CONSTRAINT [PK_MyTable] PRIMARY KEY CLUSTERED([MyTableId] ASC,[MyDate] ASC)
)
GO
CREATE PROCEDURE ProcTopDate
(
#MyDate datetime OUT
)
AS
BEGIN
SET NOCOUNT ON;
SELECT TOP 1
#MyDate = [MyDate]
FROM [Test].[dbo].[MyTable]
order by MyDate
END
GO
insert into MyTable(MyTableId, MyDate)
values(newid(), getdate())
go
declare #MyDate datetime
exec ProcTopDate #MyDate OUT
print #MyDate
Instead of SELECT TOP 1 ... ORDER BY ...
Why not try SELECT MAX( ..
DECLARE #dtTopDate datetime
SELECT #dtTopDate = MAX(date_build)
from database..table
where database..table.parent = #Parent
and database..table.child = #Child
What version of SQL are you using? It works fine for me on MS SQL Server 2005 (ionce I fix the declaration).
Honestly the only thing I can see wrong is that #dtTopDate =/= #dtLatestDate
Apart from that, there is no GROUP BY clause in your SQL statement.
I just ran this and it worked fine.
declare #OrderDate datetime
select top 1 #OrderDate = OrderDate
from Orders
where Orders.CustomerID = 'ALFKI'
and Orders.EmployeeID = 4
order by OrderDate desc
SELECT #OrderDate
Try qualifying the columns correctly to avoid any ambiguities or x-database schema issue
declare #dtTopDate datetime
select top 1
#dtTopDate = [database]..[table].date_build
FROM
[database]..[table]
where
[database]..[table].parent = #Parent
and [database]..[table].child = #Child
order by
[database]..[table].date_build desc
Or alias it
declare #dtTopDate datetime
select top 1
#dtTopDate = foo.date_build
FROM
[database]..[table] foo
where
foo.parent = #Parent
and foo.child = #Child
order by
foo.date_build desc
The problem was in another part of the stored procedure. I was using a count(*) elsewhere and it required a group by. Thanks for the help.
Try SELECT #dtLatestDate = TOP 1 date_build...
if you want to get really tricky, in T-SQL you can try using the row_number() method and an inner select:
select * from
(
select
db.groupId
, db.date_build
, date_build_rank = row_number() over ( partition by db.groupId order by db.date_build desc)
from
#date_build_tbl db
) as a
where a.date_build_rank < 2;