I am running some SQL that identifies records which need to be marked for deletion and to insert a value into those records. This value must be changed to render the record useless and each record must be changed to a unique value because of a database constraint.
UPDATE Users
SET Username = 'Deleted' + (ISNULL(
Cast(SELECT RIGHT(MAX(Username),1)
FROM Users WHERE Username LIKE 'Deleted%') AS INT)
,0) + 1
FROM Users a LEFT OUTER JOIN #ADUSERS b ON
a.Username = 'AVSOMPOL\' + b.sAMAccountName
WHERE (b.sAMAccountName is NULL
AND a.Username LIKE 'AVSOMPOL%') OR b.userAccountControl = 514
This is the important bit:
SET Username = 'Deleted' + (ISNULL(
Cast(SELECT RIGHT(MAX(Username),1)
FROM Users WHERE Username LIKE 'Deleted%') AS INT)
,0) + 1
What I've tried to do is have deleted records have their Username field set to 'Deletedxxx'. The ISNULL is needed because there may be no records matching the SELECT RIGHT(MAX(Username),1) FROM Users WHERE Username LIKE 'Deleted%' statement and this will return NULL.
I get a syntax error when trying to parse this (Msg 156, Level 15, State 1, Line 2
Incorrect syntax near the keyword 'SELECT'.
Msg 102, Level 15, State 1, Line 2
Incorrect syntax near ')'.
I'm sure there must be a better way to go about this, any ideas?
If your Users table already has an integer PK column, you can simply use this column to generate 'Deleted'+PK usernames.
Btw, would the SELECT RIGHT(MAX(Username),1) not fail after 10 users? Better to use SUBSTRING().
Is it strictly necessary to use incremental 'xxx' values? Couldn't you just use random values?
SET Username = Username + '_deleted_' + CAST(NEWID() AS char(36))
Additionally, it might be a bad idea to overwrite the login completely. Given that you disable the record, not delete it entirely, I assume that you need it for audit purposes or smth. like that. In this case, records with IDs like 'Deleted1234' might be too anonymous.
I suspect this would work better as a multi-step SQL statement, but I'm unsure if that's reasonable.
The error you're seeing is because you're trying to concatenate an int to a string, you're also adding 1. Your order of operations is all screwy in that set statement. This does what you're asking, but it will fail the minute you get more than 9 deleted entries.
SELECT 'DELETED' + CAST(
ISNULL(
CAST(
SELECT RIGHT(MAX(Username),1)
FROM #Users WHERE username LIKE 'DELETED%')
AS INT)
, 0) + 1 )
AS VARCHAR(3))
edit: sorry for the horrible formatting. Couldn't figure out how to make it readable.
Related
I found this question on SO elsewhere, but the answer included a part that doesn't pertain to me, so I must ask this question with my specifics.
I need to simply add an option in my dropdown menu. Here's my SQL query to be used for the salesperson only (debug mode):
declare #user varchar(30)
set #user = 'DOMAIN\ppelzel'
select SalesPerson_Name
from Salesperson
where salesperson_id = case
when #user in ('DOMAIN\Brandyj',
'DOMAIN\jwilson','DOMAIN\KRoberts',
'DOMAIN\ppelzel','DOMAIN\bmurray')then salesperson_id
else SUBSTRING(#user,14,20)
end
order by 1
Per my previous mention of another question like this asked, it said to not use a WHERE clause. I, however, must use a WHERE clause because I need it to determine if the person logged in matches what's in the dataset, then that is the only name they'll see, outside of a handful of 'Admin' users who need to see everyone.
For these same Admin users, I need to add an option to select all salespeople. I tried simply using the "allow multiple values" but it doesn't like that and gives me an error: Incorrect syntax near ','. even when I take out the WHERE clause in my query of sp.salesperson_name = #salesperson. Anyway, what's my best course of action for adding an All option for this report?
EDIT: I just realized I might need to add the main dataset query for context:
SELECT sp.SalesPerson_Name
,c.Calendar_Month_Name
,sum(isnull(sales_qty, 0)) AS 'total gallons'
,sum(isnull(Ext_Retail_Base, 0) + isnull(Ext_Retail_Freight, 0)) - sum(isnull(Ext_Cost_Base, 0) + isnull(Ext_Cost_Freight, 0)) 'Sales GM'
,(sum(isnull(Ext_Retail_Base, 0) + isnull(Ext_Retail_Freight, 0)) - sum(isnull(Ext_Cost_Base, 0) + isnull(Ext_Cost_Freight, 0))) / sum(isnull(sales_qty, 0)) 'cpg'
FROM Fuel_Wholesale_Sales_Fact fwsf
JOIN calendar c ON fwsf.Calendar_key = c.calendar_key
JOIN Salesperson sp ON sp.SalesPerson_Key = fwsf.Salesperson_Key
JOIN Customer cu ON fwsf.Customer_Key = cu.Customer_Key
WHERE sp.SalesPerson_Name = #SalesPerson
AND c.Day_Date BETWEEN #Start
AND #End
and isnull(fwsf.sales_qty,0) != 0
GROUP BY sp.SalesPerson_Name, c.Calendar_Month_Name
UPDATE 1: I attempted to use the STRING_SPLIT function, but even using the simple example from Microsoft's website (https://learn.microsoft.com/en-us/sql/t-sql/functions/string-split-transact-sql?view=sql-server-2016) resulted in me getting an error: Invalid object name 'STRING_SPLIT'. I am running SQL 2016. Thoughts?
Figured it out. Compatibility level issue. My DB is set on 110. I may need to ask some questions if there's a reason it's set on that as opposed to the default 130.
UPDATE 2: I finally sorted out what I needed. I just used the "Allow multiple values" option in the Parameter Properties. It wasn't working before because I foolishly did not use an IN operator nor surround the parameter with parentheses.
So I had the following: select salesperson where id = #salesperson
When what I needed was: select salesperson where id in (#salesperson) because Report Builder will pass a string of parameter values as 'Bob','Mary','John' which require that they be put inside the parentheses. This is for others who come looking for answers.
I have an audit running on multiple tables in my database that is triggered when a user runs a select against said tables. I am attempting to parse the 'statement' returned from the audit and get a username out of the information. Here is my query:
SELECT *
FROM (SELECT LastName,
queryLastName,
statement,
Event_time AS CurrentDateTime,
'AuditFile' AS SourceTable
FROM (SELECT statement,
event_time,
SUBSTRING(server_principal_name, 9, len(server_principal_name) - 8) AS LastName,
SUBSTRING(SUBSTRING(statement, CHARINDEX('LastName like ''%', statement) + 16, 20), 0, CHARINDEX('%''', SUBSTRING(statement, CHARINDEX('LastName like ''', statement) + 16, 20))) AS queryLastName
FROM #MyTempTable
WHERE server_principal_name != 'abc'
AND CHARINDEX('LastName like ''%', statement) > 0) AS A) AS B
WHERE querylastname != ''
Now, the above query will correctly return any SELECT query that has Lastname like '%name%', but i'd also like to be able to return names looked up in other ways such as '%name' or '_name__'. Are there any more elegant solutions to solve this problem?
Edit: The Audit file contains a column called 'Statement'. This holds what the query was that triggered the audit. For example,
SELECT * from tblUserNames where LastName Like '%Smith%'
will trigger the audit and place the above query in statement.
My query takes Smith out of the string however if a user entered '%Smith' instead, the query would not work as it does not pick up variations. Same goes for 'Smith', 'Smith' etc. If possible, I need a more elegant way to handle multiple situations where a user could look up a name using wildcards on either end of the name.
I have been working on this project by using "advanced" features of SQL Server and creating functions, triggers, but two of these are giving me serious issues.
I am supposed to create a function that includes one input parameter and returns a table. The function itself will return a summary of the individual costs of each insurance expense (base, spouse, etc.), a total of those expenses and the employees name given the number of dependents a given employee has- the user enters the number of dependents as an input parameter.
CREATE FUNCTION fnInsCosts
(#NoDependants int)
--returns table datatype
RETURNS table
AS
--Set the Return to select the columns and aggregated columns from vwPayRoll as listed in exercise 3 of Module 12 --assignment sheet where Dependants is = to the input variable.
RETURN (SELECT
EmpName,
SUM(BaseCost) AS TotBaseCost, SUM(SpouseIns) AS TotSpouseCost,
SUM(DepIns) AS TotDepCost, SUM(DentalCost) AS TotDentalCost,
SUM(BaseCost * SpouseIns * DepIns * DentalCost) AS TotInsCost
FROM
vwPayroll
WHERE
Dependants = #NoDependants
GROUP BY
Dependants);
SELECT * FROM dbo.fnInsCosts(2);
SELECT * FROM dbo.fnInsCosts(0);-- Unfinished/error with select and EmpName?
Here is the error I get when I try to run the whole thing:
Msg 156, Level 15, State 1, Procedure fnInsCosts, Line 15
Incorrect syntax near the keyword 'SELECT'.
And it says this when I run everything except for the part where I invoke it:
Msg 8120, Level 16, State 1, Procedure fnInsCosts, Line 10
Column 'vwPayroll.EmpName' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
And here is the last one; I am creating a trigger and I need to create two table copies:
--Test for the existence of a fake table named TempEmpData. If it exists, drop it.
IF OBJECT ID('TempEmpData') IS NOT NULL
DROP TABLE TempEmpData;
--Test for the existence of a fake table named TempWork. If it exists, drop it.
IF OBJECT ID('TempWork') IS NOT NULL
DROP TABLE TempWork;
--Select everything from EmpData into the appropriate fake table
SELECT * INTO TempEmpData FROM EmpData
--Select everything from Work into the appropriate fake table
SELECT * INTO TempWork FROM Work
GO
CREATE TRIGGER TempEmpDate_INSERT_UPDATE_DELETE
ON TempEmpData
AFTER INSERT, UPDATE, DELETE
AS
--(USE THIS CONDITIONAL STRUCTURE- substitute variable names where needed and remove the "--")
IF EXISTS (SELECT * FROM Deleted JOIN TempEmpData ON Deleted.EmpID = TempEmpData.EmpID)
--the correct primary key)
BEGIN;
--Custom error message
THROW 11, 'EmpID is in use; transaction cancelled!', 1;
--rollback the transaction
ROLLBACK TRAN;
END;
ELSE
BEGIN
--Update the appropriate fake table
CREATE TRIGGER TempEmpData_INSERT_UPDATE
ON TempEmpData
AS
--Set the appropriate column to the correct value
--Where the correct primary key is in a subquery selecting that same key from the
--system table that handles inserts
UPDATE TempEmpData
SET BenPlanID = 0;
DELETE TempEmpData
WHERE EmpID = 41;
INSERT TempEmpData
VALUES ('Bill', 'Smith', '11/14/2014', 0, 0, 1, NULL, 2);
SELECT *
FROM TempEmpData
ORDER BY EmpID DESC
END;
And here are the errors:
Msg 4145, Level 15, State 1, Line 4
An expression of non-boolean type specified in a context where a condition is expected, near 'ID'.
Msg 4145, Level 15, State 1, Line 8
An expression of non-boolean type specified in a context where a condition is expected, near 'ID'.
Msg 156, Level 15, State 1, Procedure TempEmpDate_INSERT_UPDATE_DELETE, Line 17
Incorrect syntax near the keyword 'TRIGGER'.
I would be extremely grateful for any insight.
You are using the "new" inline syntax to create a function, great!
The first error comes from the missing "GO" to separate the creation of your function from the call to it
CREATE FUNCTION fnInsCosts()
--You function code here
GO
SELECT * FROM dbo.fnInsCosts(2);
The second error in your function has its reason - as stated by JamesZ already - in the wrong grouping column:
SELECT EmpName,
SUM(BaseCost) AS TotBaseCost,
SUM(SpouseIns) AS TotSpouseCost,
SUM(DepIns) AS TotDepCost,
SUM(DentalCost) AS TotDentalCost,
SUM(BaseCost * SpouseIns * DepIns * DentalCost) AS TotInsCost
FROM vwPayroll
WHERE Dependants = #NoDependants
GROUP BY EmpName
You see, that the only column which has not got any aggregation function is the EmpName...
And the last one - again stated by JamesZ already is the missing underscore in the function's name OBJECT ID:
IF OBJECT_ID('TempEmpData') IS NOT NULL
In your code T-SQL is searching for the meaning of "object" and for a function called "ID"... (The same with IF OBJECT ID('TempWork') IS NOT NULL)
And one last point: On SO it is highly advised to create one question per issue. This question should've been at least parted in two separate questions. Just think of future readers searching for similar problems...
EDIT Ups, there was even one more...
Your last error message points to some code where I do not understand what you really want to achieve... Are you creating a trigger from within the trigger? Might be, the MERGE statement was the better approach for your needs anyway...
I am working in SQL Server 2008. I have been tasked with writing a stored procedure to do some data validations on external data before we move it into our star schema data warehouse environment. One type of test requested is domain integrity / reference lookup from our external fact data tables to our dimension tables. To do this, I use the following technique:
SELECT
some_column
FROM some_fact_table
LEFT JOIN some_dimension_table
ON
some_fact_table.some_column = some_dimension_table.lookup_column
WHERE
some_fact_table.some_column IS NOT NULL
AND
some_dimension_table.lookup_column IS NULL
The SELECT clause will match the column definition for an errors table that I will eventually move the output into via SSIS. So, the SELECT clause actually looks like:
SELECT
primary_key,
'some_column' AS Offending_Column,
'not found in lookup' AS Error_Message,
some_column AS Offending_Value
But, because the fact tables are very large, we want to minimize the number of times that we have to select from it. Hence, I have just 1 query for each fact table to check each column in question, which looks something like:
SELECT
primary_key,
'col1|col2|col3' AS Potentially_Offending_Columns,
'not found in lookup|not found in lookup|not found in lookup' AS Error_Messages,
col1 + '|' + col2 + '|' + col3 AS Potentially_Offending_Values
FROM fact_table
LEFT JOIN dim_table1
ON
fact_table.col1 = dim_table1.lookup_column
LEFT JOIN dim_table2
ON
fact_table.col2 = dim_table2.lookup_column
LEFT JOIN dim_table3
ON
fact_table.col2 = dim_table3.lookup_column
WHERE
dim_table1.lookup_column IS NULL
OR
dim_table2.lookup_column IS NULL
OR
dim_table3.lookup_column IS NULL
This has some problems with it. (1) If any of the source column rows is null, then the string concatenation in Offending_Values will result in NULL. If I wrap each column with ISNULL (and swap the nulls for something like an empty string), then I won't be able to tell if the test failed because of a true empty string in the source or if it was swapped for an empty string. (2) If just one of the columns fail in the lookup, then the error message will still read 'not found in lookup|not found in lookup|not found in lookup', i.e., I can't tell which of the columns actually failed. (3) The Potentially_offending_Columns column in the output will always be static, which means I can't tell if any of the columns failed just by looking at it.
So, in effect, I am having some design problems with my errors table. Is there a standard way of outputting to an errors table in this situation? Or, if not, what do I need to fix to make the output readable and useful?
I don't know what your data looks like, but instead of using an empty string with ISNULL, couldn't you return the word FAIL or something that's meaningful to you. You could do a CASE WHEN for your 'not found in lookup' column.
CASE WHEN Col1 IS NULL THEN 'not found in lookup' ELSE '' END + '|' +
CASE WHEN Col2 IS NULL THEN 'not found in lookup' ELSE '' END + '|' +
CASE WHEN Col3 IS NULL THEN 'not found in lookup' ELSE '' END AS Error_Messages,
ISNULL(col1,'FAIL') + '|' + ISNULL(col2,'FAIL') + '|' + ISNULL(col3,'FAIL') AS Potentially_Offending_Values
On the query below I keep getting this error:
Cannot read the next data row for the dataset DataSetProject. (rsErrorReadingNextDataRow)
It appears to be the where clause, if I take it out it seems to work. So I added a cast to the where clause with no luck. Is there something special I need to do in the where clause to get this to work? Just an FYI this is in a report that is pulling an id from the url.
SELECT new_projects.new_projectsId AS ProjectId
, new_projects.new_name AS ProjectName
, new_projects.new_Description AS ProjectDescription
FROM
new_projects
LEFT OUTER JOIN new_projectsteps
ON new_projects.new_projectsId = new_projectsteps.new_ProjectSteps2Id
LEFT OUTER JOIN Task
ON new_projectsteps.new_projectstepsId = Task.RegardingObjectId
WHERE
(new_projects.new_projectsId = cast(#id AS UNIQUEIDENTIFIER))
Thanks!
EDIT:
The id in SQL is a Unique Identifier, the value of #id is being pulled from the querystring(url). So it would look like: &id='BC02ABC0-A6A9-E111-BCAD-32B731EEDD84'
Sorry for the missing info.
I suspect the single quotes are coming through. So either don't have them there by stripping them out before being passed to your parameter or use:
WHERE new_projects.new_projectsId = CONVERT(UNIQUEIDENTIFIER, REPLACE(#id, '''', ''));
If you try a direct comparison when the GUID contains other characters, you should get:
Msg 8169, Level 16, State 2, Line 1 Conversion failed when
converting from a character string to uniqueidentifier.
If this is not what's happening, then don't say "the id in SQL is a Unique Identifier" - show ALL of the code so we can try to reproduce the problem.