I have a function that returns a single row in SQL Server. Now I have several (about a couple hundred) databases on that server with the same table structure. I want to run that function on all the databases. Is it necessary to create the function in each database, or is there another way?
This is on SQL Server 2005, btw.
I'm not at liberty to post the actual function, but it's just an SQL Server function that returns a row. Something similar to this
ALTER FUNCTION [dbo].[getTotalOrdersByProductID](#ProductID bigint, #month varchar(100), #year varchar(100))
RETURNS #retTotalOrder TABLE
(
ProductID BIGINT primary key,
total int
)
AS
BEGIN;
INSERT #retTotalOrder
SELECT ProductID, count(*) AS total
FROM
PRODUCTS
WHERE PRODUCTS.orderdate BETWEEN firstDayOfMonth(#month, #year) AND lastDayOfMonth(#month, #year)
GROUP BY ProductID
RETURN
END;
Use . notation
SELECT * FROM Server.Database1.dbo.TableName WHERE example = 12345
SELECT * FROM Server.Database2.dbo.TableName WHERE example = 12345
You can UNION the results, depends what you wants from your function.
Related
I'm trying to write a stored procedure in MySQL that will query a table based on the employee's department number. If the department number is present in the table, it should return only those employees belonging to that department. On the other hand, if it's not present in the table, then I want to return all records from the table.
However, I'm not sure how to accomplish this.
Table Schema:
empNo
empName
salary
deptNo
number
name
salary
dept number
My stored procedure so far:
DELIMITER //
CREATE PROCEDURE GetEmpData(
IN deptNum INT
)
BEGIN
IF deptNum THEN
SELECT * FROM empdemo
WHERE deptNo = deptNum;
ELSE
SELECT * FROM empdemo;
END IF;
END //
I used the if else because I didn't know of any other way to break this query down. If anyone has any other suggestions please post them!
It seems that you need in this query:
SELECT *
FROM empdemo
WHERE empdemo.deptNo = deptNum
OR NOT EXISTS ( SELECT NULL
FROM empdemo
WHERE empdemo.deptNo = deptNum )
Here is the scenario: I have tables stored in my monitoring application database using IDs as part of the table name. For instance, for 10 monitored devices, the device logs are stored in tables for each device with the device ID as part of the name, like this:
Device ID Table Name
1 device_logs.log_1
2 device_logs.log_2
I want to be able to :
select * from all device log tables where ID IN (a-list-of-IDs)
I reference this type of information a lot, and it would be easier to do it in a quick query and possibly a report. For some small list of devices, a union query works, but after about 4-5 devices, that gets too long. Programmatically, I can do this in python with string substitution, but how do you do it in MySQL as a query?
Adding a code segment I am trying to get to work, but struggling with the syntax:
drop table if exists tmp_logs;
create temporary table tmp_logs
(
device_name varchar(30) not null,
date datetime,
message varchar (255)
)
engine=innodb;
drop procedure if exists load_tmp_log_data;
delimiter #
create procedure load_tmp_log_data()
begin
declare vid int unsigned;
truncate table tmp_logs;
start transaction;
while vid in(4976,4956) do
insert into tmp_logs values
( SELECT
dev.device,
date,
message
FROM device_logs.logs_vid
inner join master_dev.legend_device dev on dev.id=vid
where date >= '2014-7-1'
and message not like '%HDMI%'
and message not like '%DVI%'
and message not like '%SIP%'
and message not like '%Completed%'
and message not like '%Template%'
and message not like '%collection%'
and message not like '%Cache%'
and message not like '%Disconnect%'
and message not like '%Row removed%'
and message not like '%detailed discovery%'
and message not like '%restarted%'
and message not like '%Auto Answer%'
);
end while;
commit;
end #
delimiter ;
call load_tmp_log_data();
select * from tmp_logs order by device_name;
You cannot dynamically specify the user name as a query in regular SQL. You could use a prepare statement with dynamic SQL.
An alternative is to set up the query as:
select l.*
from ((select l.*
from device_logs.log_1 l
where device_id = 1 and id in (list of ids)
) union all
(select l.*
from device_logs.log_2 l
where device_id = 2 and id in (list of ids)
) . . .
) l;
You need to repeat the conditions in each subquery -- that makes them more efficient. And, use union all instead of union to avoid duplication.
Fundamentally, though, having tables of the same structure is often a sign of poor database design. It would be much better to have a single table with a column specifying the id. Then your query would be really easy:
select l.*
from logs l
where id in (list of ids);
You could generate such a table by changing the application that creates the tables. Or you could generate such a table by using an insert trigger on each of the subtables. Or, if the data can be a day or so out of date, run a job that re-creates the table every night.
how to write query for following request?
my table:
id designation
1 developer,tester,projectlead
1 developer
1 techlead
if id=1,designation="'developer'"
Then need to first,second records.Because 2 rows are having venkat.
if id=1,designation="'developer','techlead'" then need to get 3 records as result.
i wrote one service for inserting records to that table .so that i am maintaining one table to store all designation with same column with comas.
By using service if user pass id=1 designation="'developer','techlead'" then need to pull the above 3 records.so that i am maintaining only one table to save all designations
SP:
ALTER PROCEDURE [dbo].[usp_GetDevices]
#id INT,
#designation NVARCHAR (MAX)
AS
BEGIN
declare #idsplat varchar(MAX)
set #idsplat = #UserIds
create table #u1 (id1 varchar(MAX))
set #idsplat = 'insert #u1 select ' + replace(#idsplat, ',', ' union select ')
exec(#idsplat)
Select
id FROM dbo.DevicesList WHERE id=#id AND designation IN (select id1 from #u1)
END
You need to use the boolean operators AND and OR in conjunction with LIKE:
IF empid = 1 AND (empname LIKE '%venkat%' OR empname LIKE '%vasu%')
The above example will return all rows with empid equals 1 and empname containing venkat or vasu.
Apparently you need to create that query based on the input from user, this is just an example of how the finally query should look like.
Edit: Trying to do this within SqlServer can be quite hard so you should really change your approach on how you call the stored procedure. If you can't do this then you could try and split your designation parameter on , (the answers to this question show several ways of how to do this) and insert the values into a temporary table. Then you can JOIN on this temporary table with LIKE as described in this article.
I have a table that contains computer login and logoff events. Each row is a separate event with a timestamp, machine name, login or logoff event code and other details. I need to create a SQL procedure that goes through this table and locates corresponding login and logoff event and insert new rows into another table that contain the machine name, login time, logout time and duration time.
So, should I use a cursor to do this or is there a better way to go about this? The database is pretty huge so efficiency is certainly a concern. Any suggested pseudo code would be great as well.
[edit : pulled from comment]
Source table:
History (
mc_id
, hs_opcode
, hs_time
)
Existing data interpretation:
Login_Event = unique mc_id, hs_opcode = 1, and hs_time is the timestamp
Logout_Event = unique mc_id, hs_opcode = 2, and hs_time is the timestamp
First, your query will be simpler (and faster) if you can order the data in such a way that you don't need a complex subquery to pair up the rows. Since MySQL doesn't support CTE to do this on-the-fly, you'll need to create a temporary table:
CREATE TABLE history_ordered (
seq INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
hs_id INT,
mc_id VARCHAR(255),
mc_loggedinuser VARCHAR(255),
hs_time DATETIME,
hs_opcode INT
);
Then, pull and sort from your original table into the new table:
INSERT INTO history_ordered (
hs_id, mc_id, mc_loggedinuser,
hs_time, hs_opcode)
SELECT
hs_id, mc_id, mc_loggedinuser,
hs_time, hs_opcode
FROM history ORDER BY mc_id, hs_time;
You can now use this query to correlate the data:
SELECT li.mc_id,
li.mc_loggedinuser,
li.hs_time as login_time,
lo.hs_time as logout_time
FROM history_ordered AS li
JOIN history_ordered AS lo
ON lo.seq = li.seq + 1
AND li.hs_opcode = 1;
For future inserts, you can use a trigger like below to keep your duration table updated automatically:
DELIMITER $$
CREATE TRIGGER `match_login` AFTER INSERT ON `history`
FOR EACH ROW
BEGIN
IF NEW.hs_opcode = 2 THEN
DECLARE _user VARCHAR(255);
DECLARE _login DATETIME;
SELECT mc_loggedinuser, hs_time FROM history
WHERE hs_time = (
SELECT MAX(hs_time) FROM history
WHERE hs_opcode = 1
AND mc_id = NEW.mc_id
) INTO _user, _login;
INSERT INTO login_duration
SET machine = NEW.mc_id,
logout = NEW.hs_time,
user = _user,
login = _login;
END IF;
END$$
DELIMITER ;
CREATE TABLE dummy (fields you'll select data into, + additional fields as needed)
INSERT INTO dummy (columns from your source)
SELECT * FROM <all the tables where you need data for your target data set>
UPDATE dummy SET col1 = CASE WHEN this = this THEN that, etc
INSERT INTO targetTable
SELECT all columns FROM dummy
Without any code that you're working on.. it'll be hard to see if this approach will be any useful.. There may be some instances when you really need to loop through things.. and some instances when this approach can be used instead..
[EDIT: based on poster's comment]
Can you try executing this and see if you get the desired results?
INSERT INTO <your_target_table_here_with_the_three_columns_required>
SELECT li.mc_id, li.hs_time AS login_time, lo.hs_time AS logout_time
FROM
history AS li
INNER JOIN history AS lo
ON li.mc_id = lo.mc_id
AND li.hs_opcode = 1
AND lo.hs_opcode = 2
AND lo.hs_time = (
SELECT min(hs_time) AS hs_time
FROM history
WHERE hs_time > li.hs_time
AND mc_id = li.mc_id
)
How to count or know the number of rows a table has without scaning all the table, maybe using ROW_NUMBER?
If you need a exact count, you will need to do a COUNT(*) which will scan the clustered index.
You can get a rough count using the sys.partitions schema, as shown here http://www.kodyaz.com/articles/sql-rowcount-using-sql-server-system-view-sys-partitions.aspx
Update: To get the count into a variable:
DECLARE #cnt INT;
SELECT #cnt = SUM(rows)
FROM sys.partitions
WHERE
index_id IN (0, 1)
AND object_id = OBJECT_ID('MyDB.dbo.MyTable');
SELECT #cnt;
SELECT COUNT(*) FROM Table
will return the number of rows
There is no ROW_NUMBER in SQL Server, just Oracle. Use:
SELECT COUNT(primary_key) FROM table
Where primary key the primary key column of your table.
Since its a primary key, its is already indexed, so SQL can count it without scanning the whole table (it uses a clustered index to be precise, which is much faster than a full table scan)
You could also use sys.indexes schema, but its not accurate, and you would need database admin priviledges to access, and your application database user is not supposed to have grants in that schema
A little late to the party here, but in SQL Server 2005 on, you could also use the sp_spaceused stored procedure:
DECLARE #rowCount AS INT
DECLARE #spaceUsed TABLE(
[Name] varchar(64),
[Rows] INT,
[Reserved] VARCHAR(50),
[Data] VARCHAR(50),
[Index_Size] VARCHAR(50),
[Unused] VARCHAR(50)
)
INSERT INTO #spaceUsed EXEC sp_spaceused 'MyTableName'
SET #rowCount = (SELECT TOP 1 [Rows] FROM #spaceUsed)
SELECT #rowCount AS 'Row Count'
I've gotten into the habit of using sp_spaceused in place of SELECT COUNT(*) FROM Table because it is much faster. It will most likely not be as accurate as COUNT(*), however.
MSDN: http://msdn.microsoft.com/en-us/library/ms188776.aspx
I dont believe you mean this but ill give it a try:
select count(*) from table