I am using SQL Server 2008 R2. I have two functions under Programmatibility > Functions > Table-valued Functions.
The first one retrieves a collection of all available columns and records.
The second one filters out the first one with an Id check.
Let's say I have a Customers table.
The first function looks like this:
ALTER FUNCTION [dbo].[fnGetCustomers]()
RETURNS TABLE
AS
RETURN
SELECT
C.CustomerId AS Id,
C.CustomerName AS Name
FROM
Customers AS C
and I call it like so SELECT * FROM fnGetCustomers().
The second one looks like this:
ALTER FUNCTION [dbo].[fnGetCustomerById]
(#CustomerId AS INT)
RETURNS TABLE
AS
RETURN
SELECT *
FROM fnGetCustomers()
WHERE (Id = #CustomerId)
and I call it like so SELECT * FROM fnGetCustomerById(1).
My problem is when I add a new column to my Customers table scheme.
First I edit fnGetCustomers to include the new column like so.
ALTER FUNCTION [dbo].[fnGetCustomers]()
RETURNS TABLE
AS
RETURN
SELECT
C.CustomerId AS Id,
C.CustomerName AS Name,
C.CustomerPhone AS Phone
FROM
Customers AS C
The fnGetCustomers works fine after the modification. Though all of the other functions, like fnGetCustomerById, that depend on this specific one miss the new column. Despite using * in the selection query.
I can solve the problem by Right-Click on function > Modify > Execute! on each one of the functions.
I guess something runs internally and refreshes them.
My database uses a great number of functions that depend on this specific basic one, so it's almost impossible to locate and "modify > execute" all of them.
What can be done so the database scheme updates/refresh itself automatically?
Related
Consider the situation where I have a report(Stored Procedure) in SQL Server. I would like to know which fields and tables need to be populated in my database for that report to return rows. For a small procedure like this:
Create Procedure dbo.getWorkOrders #status nvarchar(10)
Select Member.Member_Name, Member.Member_ID, WorkOrder.Technician_ID, WorkOrder.Status
From Member Inner Join WorkOrder
on WorkOrder.Member_ID = Member.Member_ID
Where
WorkOrder.Status like #status
For the example above, I would define the required data by looking at inner joins and items in the where clause. In this example, there must be rows on the Member table with Member_ID's, there must also be rows on WorkOrder with Member_ID's and statuses. I'm not concerned if the procedure returns blank because the user enters a status that doesn't exist on the WorkOrder table, but I am concerned if the WorkOrder table was loaded rows that have no status, or if no rows were loaded for Member or WorkOrder.
To put it another way, a routine task for me is to find out what data needs to be loaded in a warehouse so that we can test the stored procedures. I'm currently doing this manually as I described in the example above, but there are many reports and tables so it's a difficult process. I would like to automate this part of my job. Does something like this already exist? If I'm going to code it, how should I start?
I was thinking about writing something in Python to extract the Inner Join and Where clauses, but if it makes sense to make a stored procedure to do this in SQL Server I would prefer that.
When creating ad-hoc queries to look for information in a table I have run into this issue over and over.
Let's say I have a table with a million records with fields id - int, createddatetime - timestamp, category - varchar(50) and content - varchar(max). I want to find all records in the last day that have a certain string in the content field. If I create a query like this...
select *
from table
where createddatetime > '2018-1-31'
and content like '%something%'
it may complete in a second because in the last day there may only be 100 records so the LIKE clause is only operating on a small number of records
However if I add one more item to the where clause...
select *
from table
where createddatetime > '2018-1-31'
and content like '%something%'
and category = 'testing'
then it could take many minutes to complete while locking up the table.
It appears to be changing from performing all the straight forward WHERE clause items first and then the LIKE on the limited set of records, over to having the LIKE clause first. There are even times where there are multiple LIKE statements and adding one more causes the query to go from a split second to minutes.
The only solutions I've found are to either generate an intermediate table (maybe temp tables would work), insert records based on the basic WHERE clause items, then run a separate query to filter by one or more LIKE statements. I've tried various JOIN and CTE approaches which usually have no improvement. Alternatively CHARINDEX also appears to work though difficult to use if trying to convert the logic of multiple LIKE statements.
Is there any hint or something that can be placed in the query statement to tell sql server to wait until records are filtered by the basic WHERE clause items before filtering by the LIKE?
I actually just tried this approach and it had the same issue...
select *
from (
select *, charindex('something', content) as found
from bounce
where createddatetime > '2018-1-31'
) t
where found > 0
while the subquery independently returns in a couple seconds, the overall query just never returns. Why is this so bad
Not fancy, but I've had better luck with temp tables than nested select statements... It will isolate the first data set, and then you can select just from that. If you're looking for quick and dirty, which usually serves my purposes for ad-hoc, this may help. If this is a permanent stored proc, the indexing suggestions may serve you better in the long run.
select *
into #like
from table
where createddatetime > '2018-1-31'
and content like '%something%'
select *
from #like
where category = 'testing'
I have a table-valued function (TVF) in SQL Server that looks like this:
CREATE FUNCTION TVF_xyz(#AuditKey INT)
RETURNS TABLE
AS
RETURN
SELECT *
FROM xyz
WHERE AUDIT_KEY = #AuditKey
GO
Now, I added a new column to the xyz table.
When I query using TVF_xyz, it doesn't show me the new column (shows all other columns except newly added).
Query:
SELECT TOP 10 *
FROM TVF_xyz (1543)
I would like to know, how to refresh TVF to show new column.
PS: Select * used in TVF to fetch all columns.
After bit of searching, I found sp_refreshsqlmodule (Transact-SQL), its common behavior of TVF.
In order to refresh TVF, following SP needs to be executed:
EXEC sys.sp_refreshsqlmodule 'TVF_xyz'
https://msdn.microsoft.com/en-us/library/bb386954(v=vs.110).aspx
The following SQL function explicitly states that it returns a TABLE. Therefore, the returned rowset structure is implicitly defined.
sample
CREATE FUNCTION ProductsCostingMoreThan(#cost money)
RETURNS TABLE
AS
RETURN
SELECT ProductID, UnitPrice
FROM Products
WHERE UnitPrice > #cost
SELECT
(
SELECT SUM(ISNULL(Volume,0))
FROM Order_【a1.Login】
WHERE Login = a1.Login
) AS SelfVolume
FROM dbo.Account a1
I want the table name in the sub-select (【a1.Login】) to match the value a1.Login from the outer select statement (field Login of table Account). How can I get this result?
The technical answer is: By using dynamic SQL. It's complicated, error-prone and potentially dangerous (beware of Bobby Tables). Your SQLs will become unreadable and unmaintainable. You are entering a world of pain.
The correct answer is: You don't. Don't create a separate Orders table for every user. Create one Orders table with a foreign key to your Account table.
If you still want to go ahead and work with this broken database design (remember: You are entering a world of pain, and you are just getting started), you will somehow need to construct the following SQL dynamically:
SELECT SUM(ISNULL(Login_Volume,0)) FROM
(
SELECT SUM(ISNULL(Volume,0)) AS Login_Volume FROM Order_SomeUser WHERE Login = 'SomeUser'
UNION ALL
SELECT SUM(ISNULL(Volume,0)) AS Login_Volume FROM Order_SomeOtherUser WHERE Login = 'SomeOtherUser'
UNION ALL
...
) AS AllSums
You can do that in the language of your choice, either in your target language (C#, Java, PHP, etc.), which is probably the easiest and most maintainable solution, or directly in T-SQL, by using T-SQL cursors and loops (= the hard way). Whichever language you choose, the algorithm is straight-forward:
Loop through your Account table and get the Logins.
Sanitize the value and validate that the corresponding Order_ table exists.
Create one SQL statement for each account.
Join them with UNION ALL.
Wrap them in the outer SELECT as shown above.
Again: If there is any chance of fixing your broken DB design instead, do that, it will pay off in the long run.
I have a table in SQL Server database. It has a column testrownum. I want to update the testrownum column to be rownum whenever row is created in the table automatically.
Is there any setting that I can turn on to achieve this?
Perhaps it is best to get a row number at the time you SELECT your data, by using the ROW_NUMBER() function.
As others have pointed out (comments section) the data in a table is essentially unordered. You can however assign a row number for a certain ordering when you select data as follows (suppose a table that only has one column being name):
SELECT
name,
rownr=ROW_NUMBER() OVER(ORDER BY name)
FROM
name_table
You can create trigger function.
Trigger is a function which is called every time data is insert, update or delete from table (you can specify when you want your function to be called when creating trigger). So you can add two triggers, one for insert and one for delete and just increment/decrement value you want.