I have 203 tables in my database and I want to write a query which returns all of the latest rows for each table - sql

I have 203 tables in my SQL database, I want to print the latest records for each table. I know the query to get the latest row of one table at one time. How do I query for the latest row of each table in one go?

Here I do not know what are the names of your DB. So I assume that they can be indexed in the way I am about to show:
DECLARE #Counter INT
SET #Counter=1
WHILE ( #Counter <= 203)
BEGIN
EXEC('SELECT TOP(5) * FROM TABLE_'+#Counter+'ORDER BY Date DESC')
SET #Counter = #Counter + 1
END
Here make sure that you have defined everything using dynamic queries. In addition, I did not know in what format you need your pulled results to look.

Use SHOW TABLES and GROUP CONCAT and
SET #Expression = SELECT CONCAT('SELECT...
SELECT GROUP_CONCAT(...
PREPARE myquery FROM #Expression;
EXECUTE myquery;
Is it possible to execute a string in MySQL?

Related

Create a stored procedure that keeps returning new rows

I have a table with x number of rows. I want to create a stored procedure that always select a new row and return that row (when all rows has been returned it will start over from first row). My idea is to select top 1 row (ordered by a date time row) return that from the stored procedure and then set an datetime column so next time it will be a new row that is returned. It needs to be thread safe so I would expect some row locking is needed (I don't know if this is true). How would you create a stored procedure like that? I am not sure of you need to use variables or it can be done in a single query. Something like:
select top 1 *
from [dbo].[AppRegistrations]
order by LastUsed
update [dbo].[AppRegistrations]
set LastUsed = getdate()
In the comments it is stated that it cannot be done in a single query. If I added following to a stored procedure will it then be thread safe? Or do I need to add a lock? And does the query make sense or should it be done differently?
declare #id int
declare #name as nvarchar(256)
select top 1 #id=id,#name=name from [dbo].[AppRegistrations] order by LastUsed
Update [dbo].[AppRegistrations] set LastUsed=getdate() where id=#id
select #id,#name
It is important that another query cannot interrupt returning a unique row because it updates a row between the select and the update. That is why I wanted it in a single query.
I tried to gather everything up and added a row lock. Following sample works as expected, but I dont know whether the row lock is the right way, or I should expect some challenges. Can someone validate if this approach is correct?
BEGIN TRAN
declare #id int
declare #name as nvarchar(256)
select top 1 #id=id,#name=name from [dbo].[AppRegistrations] WITH (HOLDLOCK, ROWLOCK) order by LastUsed
Update [dbo].[AppRegistrations] set LastUsed=getdate() where id=#id
select #id as id,#name as name
COMMIT TRAN
I make a good number of assumptions here
UPDATE [dbo].[AppRegistrations]
SET LastSelected = CURRENT_TIMESTAMP
OUTPUT INSERTED.*
WHERE Id = (SELECT TOP (1) Id
FROM [dbo].[AppRegistrations]
ORDER BY LastSelected
)
Here is some background on the OUTPUT https://learn.microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sql?view=sql-server-ver15
Here is another reference where you can do slightly more complex things https://learn.microsoft.com/en-us/sql/t-sql/queries/update-transact-sql?view=sql-server-ver15#CaptureResults

Updating a column in every table in a schema in SQL Server

I want to update the column Last_Modified in every table in a given schema. This column is updated with latest timestamp if another column in the same table (ENDTIME) is updated.
To do this I have the following script in SQL Server:
DECLARE #TotalRows FLOAT
SET #TotalRows = (SELECT COUNT(*) FROM table1)
DECLARE #TotalLoopCount INT
SET #TotalLoopCount = CEILING(#TotalRows / 100000)
DECLARE #InitialLoopCount INT
SET #InitialLoopCount = 1
DECLARE #AffectedRows INT
SET #AffectedRows = 0
DECLARE #intialrows INT;
SET #intialrows = 1
DECLARE #lastrows INT
SET #lastrows = 100000;
WHILE #InitialLoopCount <= #TotalLoopCount
BEGIN
WITH updateRows AS
(
SELECT
t1.*,
ROW_NUMBER() OVER (ORDER BY caster) AS seqnum
FROM
table1 t1
)
UPDATE updateRows
SET last_modified = ENDTIME AT TIME ZONE 'Central Standard Time'
WHERE last_modified IS NULL
AND updateRows.ENDTIME IS NOT NULL
AND updateRows.seqnum BETWEEN #intialrows AND #lastrows;
SET #AffectedRows = #AffectedRows + ##ROWCOUNT
SET #intialrows = #intialrows + 100000
SET #lastrows = #lastrows + 100000
-- COMMIT
SET #Remaining = #TotalRows - #AffectedRows
SET #InitialLoopCount = #InitialLoopCount + 1
END
This script determines the count of a table, divides it by 100000 and runs only that many loops to perform the entire update. It breaks down the update in batches/loops and then perform updates on certain rows until it completes updating them all.
This script is only for 1 table, i.e table1. I want to now modify this script in such a way that it dynamically takes all the tables in a schema and runs the above script for each of them. Let's say the schema name is schema1 and it has 32 tables, so this script should run for all those 32 tables.
I am able to retrieve the tables in schema1 but I am not able to dynamically send those to this script. Can anyone please help me with this?
To dynamically change table names at runtime you're going to need something like sp_executesql. See here for an example of its use: https://stackoverflow.com/a/3556554/22194
Then you could have an outer cursor that fetches the table names and then assembles the queries in a string and executes them. Its going to look horrible though.
If your schema doesn't change much another approach would be to generate a long script with a section for each table. You generate the script by querying the table names and then repeating the script with each different table name. Excel is actually pretty good for doing that sort of thing - paste your table names into Excel, use Excel to generate the script then copy/paste it back into SSMS.
This will be a long repetitive script but will avoid the disadvantage of having all the SQL in strings.

Pivoting Date in SQL Server

I have the following code in SQL Server that is generating a count of users by Code and by Date:
SELECT
code, CONVERT(DATE, created_at) Date, COUNT(account_id) UserCount
FROM
Code_Table
GROUP BY
code, CONVERT(DATE, created_at)
This just generates a count of users by each unique code and date combination. I'm attempting to use the Pivot function to get:
the list of unique codes in the first column
a column for each unique date, starting in the second column
a count of each user associated with the date-code combinations populating the table.
One issue I'm running into is: I would like to set this query to update automatically daily, which will add an additional column with the most recent date each day. The only pivots functions I've found require a declaration of the number of columns that are being created from rows.
I understand this would be much more easily done in Excel w/ a Pivot, but I don't currently have that option.
Any advice would be much appreciated!
You need a dynamic pivot to accomplish this. You're correct that you need an explicit column list -- so you'll query your table and actually generate SQL syntax as the result, and then execute that syntax with sp_executesql.
You can find that on Stack Overflow:
SQL Server dynamic PIVOT query?
A word of warning: This is usually not best practice. You won't be able to do any filtering or any date-related logic on this result set. Whatever front end reporting software you are using is probably where you want to implement the matrix/crosstab like behavior that you're getting from pivoting.
Try using this store procedure:
CREATE PROCEDURE GetData
-- Add the parameters for the stored procedure here
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #columns varchar(MAX) = '';
SELECT #columns = #columns + '[' + CONVERT(VARCHAR,ct.created_at) + '],'
FROM Code_Table ct
GROUP BY created_at
ORDER BY created_at ASC;
SET #columns = SUBSTRING(#columns,1,LEN(#columns) - 1);
DECLARE #query varchar(MAX)= 'SELECT
*
FROM
(SELECT code,account_id,created_at from Code_Table) AS result
PIVOT
(
COUNT(account_id) FOR created_at IN ('+ #columns +')
) p'
;
EXEC (#query)
END
I built the column's header dynamically depending of existing values of dates.

Sql update statement, any way of knowing what it actually did?

Typically, I test an update by running a query using the where statement and then after verifying that it does what I think I want it to copying the where clause to the update statement and executing it. But is there any way of getting the statement to return what the update did besides the '4 rows updated'
Sure, take a look at the output clause of T-SQL
http://msdn.microsoft.com/en-us/library/ms177564.aspx
You could load your records into a temp table/variable in SQL Server:
DECLARE #Temp TABLE(ID INT)
INSERT INTO #Temp (ID)
SELECT ID
FROM Customer
WHERE AcctBalance > 5000
--inspect as needed
UPDATE Customer
SET AcctBalance = 0
WHERE ID IN (SELECT ID FROM #Temp)
That depend in the server, library that you use, in php, pdo exec return number of row effected by delete or update cluase

Efficient SQL query for two updates and search queries

I have a query like this:
SELECT TOP 1 ID, DATA, OTHERINF FROM MYTABLE WHERE DATE = #DATE
and after reading the row data and using it I want to update that retrieved row and change one of it's columns (in another transaction).
But as you see here i searched for that row twice. Is there any way that I keep remember the row and do the update without searching again.
Thank you.
In the first query you retrieved the id. In the second query use that to find the row to update instead of using the date:
UPDATE MYTABLE
SET DATA = 'FooBar'
WHERE ID = 200
I know its out of vogue but you can also do positioned updates on cursors
e.g.
use Northwind
GO
DECLARE EMP_CURSOR CURSOR
FOR SELECT TOP 1 EmployeeID, LastName FROM EMPLOYEES WHERE HireDate = '1994-11-15'
FOR UPDATE OF LastName
OPEN EMP_CURSOR
FETCH NEXT FROM EMP_CURSOR
UPDATE EMPLOYEES
SET LastName = LastName + CAST(DatePart(ms,GetDate()) as char(3))
WHERE CURRENT OF EMP_CURSOR
CLOSE EMP_CURSOR
DEALLOCATE EMP_CURSOR
--Note, need to setup proper data types
DECLARE #Id INT
DECLARE #Data VARCHAR(MAX)
DECLARE #OtherInf VARCHAR(max)
SELECT TOP 1 #id = Id, #Data = Data, #OtherInf = OtherInf
FROM MyTable
WHERE Date = #Date
--Now you can do what you need, using the info above.
This should do it
You can combine the UPDATE with the SELECT into one statement, but not across two transactions. Therefore, if you need to update the value in another transaction than you select it (the reason for this is unclear to me), you need two statements.
I presume that the DATE column isn't indexed (if not, why not?) Your best bet, then, is to make sure you retrieve the primary key (isn't that ID?) and then use that as your condition in the update.