Service Broker only receiving one message at a time - tsql

Even when I specify Receive Top(25), etc I am only getting one message to be dequeued at a time. Not sure what i am doing wrong inside my sproc? Probably something trivial, but I don't see the problem.
Sproc:
CREATE PROCEDURE dbo.SPP_DEQUEUE_MESSAGE
AS
BEGIN
DECLARE #receiveTable TABLE(
message_type sysname,
message_body xml,
message_dialog uniqueidentifier);
BEGIN TRANSACTION;
WAITFOR
( RECEIVE TOP(25)
message_type_name,
message_body,
conversation_handle
FROM TargetQueue1DB
INTO #receiveTable
), TIMEOUT 3000;
SELECT
*
From #receiveTable;
Delete from #receiveTable;
COMMIT TRANSACTION;
END --End Sproc
Any idea what I am doing wrong?
Thanks,
B

My guess would be that each message belongs to a different conversation (and therefore by default to a different conversation group). If this is the case, then this is expected behavior.
From Books Online - Receive (Transact-SQL):
All messages that are returned by a
RECEIVE statement belong the same
conversation group
If you want to receive multiple messages at once, send multiple messages on a single conversation or group multiple conversations into a single conversation group on the receiving end.

Do you know how many messages are in that queue, before the proc is run?
If you run the following query to get the count in all your queues
SELECT sq.name,
p.rows
FROM sys.service_queues sq
Join sys.internal_tables it ON sq.object_id = it.parent_id
AND it.parent_minor_id = 0
AND it.internal_type = 201
Join sys.indexes as i on i.object_id = it.object_id and i.index_id = 1
Join sys.partitions as p on p.object_id = i.object_id and p.index_id = i.index_id
WHERE
sq.object_id = it.parent_id AND
it.parent_minor_id = 0 AND
it.internal_type = 201
If there is more than 1 message in that queue, you should get more than 1 in your receive.

Related

Get postgres query log statement and duration as one record

I have log_min_duration_statement=0 in config.
When I check log file, sql statement and duration are saved into different rows.
(Not sure what I have wrong, but statement and duration are not saved together as this answer points)
As I understand session_line_num for duration record always equals to session_line_num + 1 for relevant statement, for same session of course.
Is this correct? is below query reliable to correctly get statement with duration in one row?
(csv log imported into postgres_log table):
WITH
sql_cte AS(
SELECT session_id, session_line_num, message AS sql_statement
FROM postgres_log
WHERE
message LIKE 'statement%'
)
,durat_cte AS (
SELECT session_id, session_line_num, message AS duration
FROM postgres_log
WHERE
message LIKE 'duration%'
)
SELECT
t1.session_id,
t1.session_line_num,
t1.sql_statement,
t2.duration
FROM sql_cte t1
LEFT JOIN durat_cte t2
ON t1.session_id = t2.session_id AND t1.session_line_num + 1 = t2.session_line_num;

SSRS SQL-Restart subscription runs all scheduled Reports

I am using the folling SQL-Script to restart faild SSRS mailing subscriptions:
DECLARE #ScheduledReportName varchar(200)
DECLARE #JobID uniqueidentifier
DECLARE #LastRunTime datetime
Declare #JobStatus Varchar(100)
--------------------------------------------------------
DECLARE #RunAllReport CURSOR
SET #RunAllReport = CURSOR FAST_FORWARD
FOR
SELECT
CAT.[Name] AS RptName
, res.ScheduleID AS JobID
, sub.LastRuntime
, CASE WHEN job.[enabled] = 1 THEN 'Enabled'
ELSE 'Disabled'
END AS JobStatus
FROM
dbo.Catalog AS cat
INNER JOIN dbo.Subscriptions AS sub
ON CAT.ItemID = sub.Report_OID
INNER JOIN dbo.ReportSchedule AS res
ON CAT.ItemID = res.ReportID
AND sub.SubscriptionID = res.SubscriptionID
INNER JOIN msdb.dbo.sysjobs AS job
ON CAST(res.ScheduleID AS VARCHAR(36)) = job.[name]
INNER JOIN msdb.dbo.sysjobschedules AS sch
ON job.job_id = sch.job_id
INNER JOIN dbo.Users U
ON U.UserID = sub.OwnerID
----------------Filter der Subscriptions----------------
where sub.subscriptionid in
(
SELECT subscriptionid
FROM Subscriptions AS S
LEFT OUTER JOIN [Catalog] AS C
ON C.ItemID = S.Report_OID
WHERE S.LastStatus like 'Failure sending mail%'
)
----------------Filter der Subscriptions----------------
ORDER BY U.UserName, RptName
OPEN #RunAllReport
FETCH NEXT FROM #RunAllReport
INTO #ScheduledReportName,#JobID,#LastRunTime,#JobStatus
WHILE ##FETCH_STATUS = 0
BEGIN
Print #ScheduledReportName --&' ' & #JobID
EXEC msdb.dbo.sp_start_job #job_name =#JobID
FETCH NEXT FROM #RunAllReport
INTO #ScheduledReportName,#JobID,#LastRunTime,#JobStatus
END
CLOSE #RunAllReport
DEALLOCATE #RunAllReport
I run this if an subscripton fails. In my example I send the same Report to multiple persons as a subscription with differen parameters. Sometime one subscription fails and I want to restart the job. The query in the upper script provides the specific subscriptionID of the failed one.
But even though the ScheduleID is handed over AS JobID all the Reports are beeing resend to all people.
Is there something wrong with the script?
Pleas help me.
Turns out that the procedure in my old query:
EXEC msdb.dbo.sp_start_job #job_name =#JobID
Runs all the Subscriptions under a ScheduleID AS JobID. So all Report with a SharedSchedule are launched again, by a job restart.
To restart only a specific supbscription I have to run the following command at its place, with the subscriptionID instead of the scheduleID:
exec [dbo].[AddEvent] 'TimedSubscription', #SubscriptionID;
This will add an event into the [dbo].[Event] table that will run the subscription passed in the parameter. So only the required Report will be sent.

How to use CASE clause (DB2) to display values from a different table?

I'm working in a bank so I had to adjust the column names and information in the query to fit the external web, so if there're any weird mistakes know it is somewhat fine.
I'm trying to use the CASE clause to display data from a different table, I know this is a workaround but due to certain circumstances I'm obligated to use it, plus it is becoming interesting to figure out if there's an actual solution.
The error I'm receiving for the following query is:
"ERROR [21000] [IBM][CLI Driver][DB2] SQL0811N The result of a scalar
fullselect, SELECT INTO statement, or VALUES INTO statement is more
than one row."
select bank_num, branch_num, account_num, client_id,
CASE
WHEN exists(
select *
from bank.services BS
where ACCS.client_id= BS.sifrur_lakoach
)
THEN (select username from bank.services BS where BS.client_id = ACCS.client_id)
ELSE 'NONE'
END username_new
from bank.accounts accs
where bank_num = 431 and branch_num = 170
EDIT:
AFAIK we're using DB2 v9.7:
DSN11015 - DB21085I Instance "DB2" uses "64" bits and DB2 code release "SQL09075" with
level identifier "08060107".
Informational tokens are "DB2 v9.7.500.702", "s111017", "IP23287", and Fix Pack "5".
Use listagg function to include all results.
select bank_num, branch_num, account_num, client_id,
CASE
WHEN exists(
select *
from bank.services BS
where ACCS.client_id= BS.sifrur_lakoach
)
THEN (select LISTAGG(username, ', ') from bank.services BS
where BS.client_id = ACCS.client_id)
ELSE 'NONE'
END username_new
from bank.accounts accs
where bank_num = 431 and branch_num = 170

How can I select * WHERE & receive other results connected to the found primary keys?

So I've got the following tables setup:
thread:
id
created_at
thread_users:
id
thread_id -> FK thread
user_id -> FK users (the user who is in the thread)
joined_at
users:
id
name
etc...other relevant details for user
Current functionality: When a user clicks on another user (e.g there FRIEND in the app), it will open the message thread between the 2 users (it should grab the msgs between the 2 users). To determine WHICH thread to use (we need to find the thread_id between the 2 users), we must query the thread_users table using the HTTP_REQUEST_USER (user who sent the GET request) & and the user_id PARAM passed in the http GET request.
Once I do this: select * from thread_users where user_id = HTTP_REQUEST_USER_ID OR user_id = GET_REQUEST_PARAM_USER_ID
It will return a bunch of threads that the users are in, I then group the returned results using the lodash groupBy method: (which basically MOVES all the results into there corresponding thread objects - E.g 6: [ { user1 }, { user2 } ] - This represents the thread_id 6)
const groupedThreads = _.groupBy(foundThreadUsers, 'thread_id');
From here I loop through each of the found threads (groupedThreads will contain objects THAT contain the arrays of user in each of the threads)
Object.keys(groupedThreads).forEach((key) => {
const thr = groupedThreads[key].filter(tu => tu.user_id === currentUserId || tu.user_id === userId);
console.log(thr, 'FOUND THREAD inside loop after filter');
/**
* #TODO add something here which will take into account pluralbot
*/
if (thr.length === 2) {
foundThread = thr[0];
}
});
However, this bit of logic doesn't work:
if (thr.length === 2) {
foundThread = thr[0];
}
Because the select * from ... (query listed above ^^), only returns the thread_users that match the user ids passed into the where user_id = x OR user_id = y.
I want to be able to select * from thread_users where user_id = HTTP_REQUEST_USER_ID OR user_id = GET_REQUEST_PARAM_USER_ID BUT also return the other users WHO match the found thread_users.thread_id. Is this possible? Or is there another way I could find the thread between the 2 users?
This is the trivial solution using a normal relational data model. (you could combine the two EXISTS() conditions) :
SELECT *
FROM thread th
WHERE EXISTS (
SELECT *
FROM user_thread ut
WHERE ut.thread_id = th.id
AND ut.user_id = ***user1***
)
AND EXISTS (
SELECT *
FROM user_thread ut
WHERE ut.thread_id = th.id
AND ut.user_id = ***user2***
)
;
This will get you the answer you're looking for:
SELECT DISTINCT -- Use DISTINCT to avoid getting duplicates for inverse pairing
T.id
FROM thread T
INNER JOIN thread_users U1
ON T.id = U1.thread_id
INNER JOIN thread_users U2
ON T.id = U2.thread_id
WHERE U1.user_id = #FirstUserID
AND U2.user_id = #SecondUserID
Okay so what I ended up doing was adding a new field to the thread table named: thread_name. The thread name consists of the 2 user ids joined together, e.g: 445-123. The reason for this is so I can easily query for a thread between 2 users! I'm not sure if I will do this for group messages though (we will see when the time comes).
Example usage:
const name = [http_req_userId, otherUserId].sort().join('-'); // Returns something like 123-323
select * from threads where thread_name = name;
Note that I'm sorting the 2 IDS before joining them together so I don't create duplicate threads between users.
I got the idea for this off this SO question (see comments of below answer): thread messaging system database schema design
EDIT
Do not use this approach - I will leave this here as a reference for what NOT to do.

Update big amount of data postgresql

The main table used is transaction, and can store million rows (let's say 4-5 million max). I need to update a status as fast as possible.
The update query looks like this :
UPDATE transaction SET transaction.status = 'TO_EXECUTE'
WHERE transaction.id IN (SELECT transaction.id FROM transaction
JOIN anotherTable ON transaction.id = anotherTable.id
JOIN anotherTable2 ON transaction.serviceId = ontherTable2.id
WHERE transaction.status = :filter1, transaction.filter2 = :filter2, ...)
Do you have a better solution? Could it be better to create another table to store the status an the id ? (I red that updating large Tables can be really slow).
The IN part of your query could likely be re-written as "exists" to potentially get improvements, depending on the other table layouts and volume. Also, it's highly possible that you do not need the transaction table mentioned yet again in the sub query (exists or in)
UPDATE transaction tx SET transaction.status = 'TO_EXECUTE'
WHERE exists (SELECT *
FROM anotherTable
JOIN anotherTable2 ON tx.serviceId = anotherTable2.id
WHERE anothertable.id=tx.id and
transaction.status = :filter1 and transaction.filter2 = :filter2,
...)
try this:
UPDATE transaction
SET transaction.status = 'TO_EXECUTE'
From anotherTable
JOIN anotherTable2 ON transaction.serviceId = anotherTable2.id
WHERE transaction.id = anotherTable.id AND transaction.status = :filter1, transaction.filter2 = :filter2, ...