Iam quite new to functions in SQL and I would like to create a function to compare values in a MySQL table against previous and I am not sure how to do this.
For example (iId is the input value)
DECLARE pVal INT(20);
DECLARE val INT(20);
SELECT price INTO pVal FROM products WHERE Id=iId;
SELECT price FROM products;
IF price == pVal THEN
SET val = price;
END IF;
Thanks
I was not sure how to run a select query on a table and then return from that function return multiple values once they have been manipulated. Also I was unsure if you could run a SELECT query in a function that returns more than one row. The first answer is that you can not return an array of data or I think more than one row from a function. Therefore I think the best way to do this is to create a temporary table with the new dataset returned.
Example
DROP TEMPORARY TABLE IF EXISTS employeeTemp;
CREATE TEMPORARY TABLE employeeTemp AS
SELECT id,start_date
FROM employee;
Secondly the answer is yes you can run a SELECT query inside a function to return more than one row.
Sorry about this I am quite new to MySQL functions.
Related
I need to create a temp table that is created by looping through a table of numbers and then adding values to the the temp table that pass a stored procedure check.
If this was C# I would write the following:
List<string> tempString = new List<string>;
foreach(var order in OrderList.Orders)
{
if (ShipOrder(order) == true)
tempString.Add(order.OrderId);
}
Or maybe pseudo code would be a better explanation.
Loop through each order in a table of orders. For each order that the stored procedure ShipOrder returns true for add to a temp table of OrdersToShip. Later use the table of OrdersToShip to do an update.
Please note this is a simple version of what I am doing. The procedure to determine if something should be shipped is rather complicated.
Oracle SQL knows no boolean data type, so your function ShipOrder will have to return something else, maybe numbers 1/0 or strings 'Y'/'N', 'TRUE'/'FALSE'. Apart from that, you simply want to select order IDs:
To insert rows into an existing table:
insert into orders_to_ship (orderid)
select orderid
from orders
where shiporder(orderid) = 'TRUE';
Or to create the not yet existing table on-the-fly:
create table orders_to_ship as
select orderid
from orders
where shiporder(orderid) = 'TRUE';
You see you don't need loops in SQL, because you are just describing the data sets you want. And usually you don't need temporary tables either :-)
I want to create a column based on COUNT(*) on another table, and when a record is deleted from that table it should decrease the value in this new column and vice versa. So, here is the query:
SELECT COUNT (*) FROM dbo.Korisnik1_FakturaStavka GROUP BY dbo.Korisnik1_FakturaStavka.FakturaID
And it returns this:
And when I try to create a computated column like this:
CREATE TABLE test(
NumberOF as (SELECT COUNT (*) FROM dbo.Korisnik1_FakturaStavka GROUP BY dbo.Korisnik1_FakturaStavka.FakturaID) )
I get the following error:
Subqueries are not allowed in this context. Only scalar expressions are allowed.
Here is the main table that I want to compute from:
How can I resolve this ?
You can define a UDF:
create function dbo.NumberOfFakturaID(#id int) returns int as begin
return (select count(1) from Korisnik1_FakturaStavka where id=#id)
end
and then use it as the computed column:
CREATE TABLE test(FakturaID int, NumberOF as dbo.NumberOfFakturaID(FakturaID))
But putting that sort of calc as a computed column should be used with care.
This is too long for a comment.
You can do this by defining a function to calculate the count and using that function in the computed column definition. However, I don't think this is a good idea for frequently used columns, because you will be doing a lot of counting "behind the scenes".
Alternatives:
Set up a view or materialized view with the additional count column.
Do the count explicitly when you need it.
Set up a trigger to store the count in the first table, whenever rows are inserted/updated/deleted from the second table.
So I've found myself with a need to have a field in my table that is a count of all the 'Shops' in another table. The table should therefore consist of Centre_Name, Location and Shop_Count. I've already created the table, so how do I add such a field?
The field should also obviously update when a shop is added or deleted in the other table. Also, each shop has a corresponding Centre_Name.
The table is in a SQL Server Express database, linked to my MVC 4 project in Visual Studio.
Thanks!
It's pretty heavy denormalization, but you could make a function to get the count and then use that function as part of a computed column. See: define a computed column reference another table
So you'd want to do:
CREATE FUNCTION dbo.CountShops (#Centre_Name VARCHAR[x])
RETURNS INT
AS BEGIN
DECLARE #ShopCount INT
SELECT #ShopCount = COUNT(*) FROM dbo.Shops WHERE Centre_Name = #Centre_Name
RETURN #ShopCount
END
And then call that as part of your column:
ALTER TABLE dbo.Shops
ADD Shop_Count AS dbo.CountShops(Centre_Name)
...this is assuming Centre_Name is the defining attribute of what you're counting shops by. What are you counting shops by? If it's just counting rows in the shops table, you could drop the parameter and do:
CREATE FUNCTION dbo.CountShops ()
RETURNS INT
AS BEGIN
DECLARE #ShopCount INT
SELECT #ShopCount = COUNT(*) FROM dbo.Shops
RETURN #ShopCount
END
More on computed columns here.
You can return a single table from a T-SQL Function in SQL Server 2008.
I am wondering if it is possible to return more than one table.
The scenario is that I have three queries that filter 3 different tables. Each table is filtered against 5 filter tables that I would like to return from a function; rather than copy and paste their creation in each query.
An simplified example of what this would look like with copy and paste:
FUNCTION GetValuesA(#SomeParameter int) RETURNS #ids TABLE (ID int) AS
WITH Filter1 As ( Select id FROM FilterTable1 WHERE Attribute=SomeParameter )
, Filter2 As ( Select id FROM FilterTable2 WHERE Attribute=SomeParameter )
INSERT INTO #IDs
SELECT ID FROM ValueTableA
WHERE ColA IN (SELECT id FROM Filter1)
AND ColB IN (SELECT id FROM Filter2)
RETURN
-----------------------------------------------------------------------------
FUNCTION GetValuesB(#SomeParameter int) RETURNS #ids TABLE (ID int) AS
WITH Filter1 As ( Select id FROM FilterTable1 WHERE Attribute=SomeParameter )
, Filter2 As ( Select id FROM FilterTable2 WHERE Attribute=SomeParameter )
INSERT INTO #IDs
SELECT ID FROM ValueTableB
WHERE ColA IN (SELECT id FROM Filter1)
AND ColB IN (SELECT id FROM Filter2)
AND ColC IN (SELECT id FROM Filter2)
RETURN
So, the only difference between the two queries is the Table being filtered, and HOW (the Where clause).
I would like to know if I could return Filter1 & Filter2 from a function. I am also open to suggestions on different ways to approach this problem.
No.
Conceptually, how would you expect to handle a function that returned a variable number of tables? You would JOIN on two tables at once? What if the returned fields don't line up?
Is there some reason you can't have a TVF for each filter?
As others say, NO. A function in TSQL must return exactly one result (although that result can come in the form of a table with numerous values).
There are a couple of ways you could achieve something similar though. A stored procedure can execute multiple select statements and deliver the results up to whatever called it, whether that be an application layer or something like SSMS. Many libraries require you to add additional commands to access more result sets though. For instance, in Pyodbc to access result sets after the first one you need to call cursor.nextset()
Also, inside a function you could UNION several result sets together although that would require each result set to have the same columns. One way to achieve that if they have a different column structure is to add in nulls for the missing columns for each select statement. If you needed to know which select statement returned the value, you could also add a column which indicated that. This should work with your simplified example since in each case it is just returning a single ID column, but it could get awkward very quickly if the column names or types are radically different.
I'm using stored procedure to fetch data and i needed to filter dynamically. For example if i dont want to fetch some data which's id is 5, 10 or 12 im sending it as string to procedure and im converting it to table via user defined function. But i must consider performance so here is a example:
Solution 1:
SELECT *
FROM Customers
WHERE CustomerID NOT IN (SELECT Value
FROM dbo.func_ConvertListToTable('4,6,5,1,2,3,9,222',','));
Solution 2:
CREATE TABLE #tempTable (Value NVARCHAR(4000));
INSERT INTO #tempTable
SELECT Value FROM dbo.func_ConvertListToTable('4,6,5,1,2,3,9,222',',')
SELECT *
FROM BusinessAds
WHERE AdID NOT IN (SELECT Value FROM #tempTable)
DROP TABLE #tempTable
Which solution is better for performance?
You would probably be better off creating the #temp table with a clustered index and appropriate datatype
CREATE TABLE #tempTable (Value int primary key);
INSERT INTO #tempTable
SELECT DISTINCT Value
FROM dbo.func_ConvertListToTable('4,6,5,1,2,3,9,222',',')
You can also put a clustered index on the table returned by the TVF.
As for which is better SQL Server will always assume that the TVF will return 1 row rather than recompiling after the #temp table is populated, so you would need to consider whether this assumption might cause sub optimal query plans for the case that the list is large.