Postgres get related post with fallback - postgresql

I wanted to get related posts from my table.So I tried some code like below
"SELECT post,category FROM library WHERE title LIKE '%" + query + "%' LIMIT 20"
Now sometimes it returns 20 results , but sometimes less than 20 , So when response is less than 20 , I need to fill with random posts which has category I mention , For example something like below
SELECT post,category FROM library WHERE category = 'php' OFFSET floor(random()*20) LIMIT 20;
For example if my search query returns 5 results , it should get random 15 posts based on my 2nd query.

Perhaps you can use UNION ALL?
SELECT * FROM (
(SELECT post,category
FROM library
WHERE title LIKE '%" + query + "%' LIMIT 20)
UNION ALL
(SELECT post,category
FROM library
WHERE category = 'php' OFFSET floor(random()*20) LIMIT 20)
) LIMIT 20;

Related

How to find the page number a record is in, in a set of paged records

I have paged SQL query that is like this
SELECT cistranm.transactionid AS transactionid
,cistranm.TransactionGroupId AS TransactionGroupId
,cisdata.id AS dCPrimaryKey
FROM dbo.cismiscalculations AS calc
INNER JOIN dbo.cismisdata AS cisdata ON calc.cismisdataid = cisdata.id
INNER JOIN dbo.cistransactionmessage AS cistranm ON cisdata.cistransactionmsgid = cistranm.id
INNER JOIN dbo.cistransactionmessagestatus AS cistrans ON cistranm.id = cistrans.cistransactionmessageid
WHERE convert(DATE, cistranm.transactioncompletiontimestamp) = convert(DATE, #LastRunDateTime)
ORDER BY cistranm.transactioncompletiontimestamp
,calc.id
,calc.earneddate offset(#PageNumber - 1) * #RowsOfPage rows
Here I supply the PageNumber and the expected rows per page (Page number can be 1 through 10, expected rows is always 1000)
Lets say on page 5 I have a transactionid as abc123. How can modify this query to return me the page number "5" if I supply the transactionId ?
Thanks in advance
For those looking but not sure what/where to ask this is how you can find what page a paged record might be in
FLOOR(CAST((CAST(T.row_num as decimal) / CAST(#RowsOfPage as decimal)) as decimal)) as page_num
FROM
(
SELECT...

JPA Query with GROUP BY, HAVING and COUNT

So the query below is probably not the most efficient, buy still, I am wondering why it is returning no result, even though the SQL counterpart does. There is no error, I am just getting no result. Is it maybe not the correct equivalent for the query I wrote in MySQL?
This is the JPA JPQL.
Query query = em.createQuery("SELECT sub FROM Subscription sub WHERE "
+ "sub.isSuspended = 0 AND "
+ "(SELECT i FROM Invoice i WHERE i.dateDue < CURRENT_DATE AND i.datePaid IS NULL "
+ "GROUP BY i HAVING COUNT(i.idInvoice) > 2) MEMBER OF sub.invoices");
And this is the SQL from MySQL.
SELECT * from subscription
WHERE subscription.is_suspended = 0 AND id_subscription IN
(SELECT id_subscription FROM invoice
WHERE date_due < CURDATE() AND date_paid IS NULL
GROUP BY id_subscription
HAVING COUNT(*) > 2)
The two queries are not the same. To use the actual query use the NativeQuery createNativeQuery() instead of Query.
In your case the JPA version seems to have syntax errors.
After the AND you are missing the IN operator.
In the nested query you are selecting i instead of something like i.idInvoice
The JPA query should look like
SELECT sub FROM Subscription sub
WHERE sub.isSuspended = 0
AND sub.idSubscription IN
(SELECT i.idInvoice
FROM Invoice i
WHERE i.dateDue < CURRENT_DATE AND i.datePaid IS NULL
GROUP BY i.idInvoice
HAVING COUNT(i.idInvoice) > 2);

Count previous occurences of a value split by date ranges

Here's a simple query we do for ad hoc requests from our Marketing department on the leads we received in the last 90 days.
SELECT ID
,FIRST_NAME
,LAST_NAME
,ADDRESS_1
,ADDRESS_2
,CITY
,STATE
,ZIP
,HOME_PHONE
,MOBILE_PHONE
,EMAIL_ADDRESS
,ROW_ADDED_DTM
FROM WEB_LEADS
WHERE ROW_ADDED_DTM BETWEEN #START AND #END
They are asking for more derived columns to be added that show the number of previous occurences of ADDRESS_1 where the EMAIL_ADDRESS matches. But they want is for different date ranges.
So the derived columns would look like this:
,COUNT_ADDRESS_1_LAST_1_DAYS,
,COUNT_ADDRESS_1_LAST_7_DAYS
,COUNT_ADDRESS_1_LAST_14_DAYS
etc.
I've manually filled these derived columns using update statements when there was just a few. The above query is really just a sample of a much larger query with many more columns. The actual request has blossomed into 6 date ranges for 13 columns. I'm asking if there's a better way then using 78 additional update statements.
I think you will have a hard time writing a query that includes all of these 78 metrics per e-mail address without actually creating a query that hard-codes the different choices. However you can generate such a pivot query with dynamic SQL, which will save you some keystrokes and will adjust dynamically as you add more columns to the table.
The result you want to end up with will look something like this (but of course you won't want to type it):
;WITH y AS
(
SELECT
EMAIL_ADDRESS,
/* aggregation portion */
[ADDRESS_1] = COUNT(DISTINCT [ADDRESS_1]),
[ADDRESS_2] = COUNT(DISTINCT [ADDRESS_2]),
... other columns
/* end agg portion */
FROM dbo.WEB_LEADS AS wl
WHERE ROW_ADDED_DTM >= /* one of 6 past dates */
GROUP BY wl.EMAIL_ADDRESS
)
SELECT EMAIL_ADDRESS,
/* pivot portion */
COUNT_ADDRESS_1_LAST_1_DAYS = *count address 1 from 1 day ago*,
COUNT_ADDRESS_1_LAST_7_DAYS = *count address 1 from 7 days ago*,
... other date ranges ...
COUNT_ADDRESS_2_LAST_1_DAYS = *count address 2 from 1 day ago*,
COUNT_ADDRESS_2_LAST_7_DAYS = *count address 2 from 7 days ago*,
... other date ranges ...
... repeat for 11 more columns ...
/* end pivot portion */
FROM y
GROUP BY EMAIL_ADDRESS
ORDER BY EMAIL_ADDRESS;
This is a little involved, and it should all be run as one script, but I'm going to break it up into chunks to intersperse comments on how the above portions are populated without typing them. (And before long #Bluefeet will probably come along with a much better PIVOT alternative.) I'll enclose my interspersed comments in /* */ so that you can still copy the bulk of this answer into Management Studio and run it with the comments intact.
Code/comments to copy follows:
/*
First, let's build a table of dates that can be used both to derive labels for pivoting and to assist with aggregation. I've added the three ranges you've mentioned and guessed at a fourth, but hopefully it is clear how to add more:
*/
DECLARE #d DATE = SYSDATETIME();
CREATE TABLE #L(label NVARCHAR(15), d DATE);
INSERT #L(label, d) VALUES
(N'LAST_1_DAYS', DATEADD(DAY, -1, #d)),
(N'LAST_7_DAYS', DATEADD(DAY, -8, #d)),
(N'LAST_14_DAYS', DATEADD(DAY, -15, #d)),
(N'LAST_MONTH', DATEADD(MONTH, -1, #d));
/*
Next, let's build the portions of the query that are repeated per column name. First, the aggregation portion is just in the format col = COUNT(DISTINCT col). We're going to go to the catalog views to dynamically derive the list of column names (except ID, EMAIL_ADDRESS and ROW_ADDED_DTM) and stuff them into a #temp table for re-use.
*/
SELECT name INTO #N FROM sys.columns
WHERE [object_id] = OBJECT_ID(N'dbo.WEB_LEADS')
AND name NOT IN (N'ID', N'EMAIL_ADDRESS', N'ROW_ADDED_DTM');
DECLARE #agg NVARCHAR(MAX) = N'', #piv NVARCHAR(MAX) = N'';
SELECT #agg += ',
' + QUOTENAME(name) + ' = COUNT(DISTINCT '
+ QUOTENAME(name) + ')' FROM #N;
PRINT #agg;
/*
Next we'll build the "pivot" portion (even though I am angling for the poor man's pivot - a bunch of CASE expressions). For each column name we need a conditional against each range, so we can accomplish this by cross joining the list of column names against our labels table. (And we'll use this exact technique again in the query later to make the /* one of past 6 dates */ portion work.
*/
SELECT #piv += ',
COUNT_' + n.name + '_' + l.label
+ ' = MAX(CASE WHEN label = N''' + l.label
+ ''' THEN ' + QUOTENAME(n.name) + ' END)'
FROM #N as n CROSS JOIN #L AS l;
PRINT #piv;
/*
Now, with those two portions populated as we'd like them, we can build a dynamic SQL statement that fills out the rest:
*/
DECLARE #sql NVARCHAR(MAX) = N';WITH y AS
(
SELECT
EMAIL_ADDRESS, l.label' + #agg + '
FROM dbo.WEB_LEADS AS wl
CROSS JOIN #L AS l
WHERE wl.ROW_ADDED_DTM >= l.d
GROUP BY wl.EMAIL_ADDRESS, l.label
)
SELECT EMAIL_ADDRESS' + #piv + '
FROM y
GROUP BY EMAIL_ADDRESS
ORDER BY EMAIL_ADDRESS;';
PRINT #sql;
EXEC sp_executesql #sql;
GO
DROP TABLE #N, #L;
/*
Now again, this is a pretty complex piece of code, and perhaps it can be made easier with PIVOT. But I think even #Bluefeet will write a version of PIVOT that uses dynamic SQL because there is just way too much to hard-code here IMHO.
*/

SQL query for two possible values?

I am using SSMS 2008 R2 and am trying to figure out the SQL select statement to select all records where two or more of the values are found.
These are the four possible values I am looking for. If two or more of these values (SubstanceAbuse, BehaviorEmotion, SexualAbuse, DomesticViolence) are met, I want to set a new field to 1. How do I do this?
case when qav.[test_setup_details_caption] in ('Substance Abuse / Drug Use','Caregiver monitor youth for drug alcohol use') then 1 else 0 end SubstanceAbuse,
case when qav.[test_setup_details_caption] in ('Physical Aggression','Firesetting','Gang Involvement','Runaway Behavior') then 1 else 0 end BehaviorEmotion,
case when qav.[test_setup_details_caption] = 'Problem Sexual Behavior' then 1 else 0 end SexualAbuse,
case when qav.[test_setup_details_caption] LIKE '%Domestic%' then 1 else 0 end DomesticViolence,
My suggestion would be to take the above statement and make it a virtual table in a new SELECT statement. Then you can do a SUM on the ones (since they are calculated already) in your WHERE statement and display only
where (Sub + Beh + Sex + Dom) > 1
It would look something like this (pseudo-code):
SELECT t.*
FROM (SELECT sub case, Beh case, etc.
FROM yourtable) t
WHERE (t.sub + t.Beh + t.Sex + t.Dom) > 1
It seems like all you need is this WHERE clause:
WHERE SubstanceAbuse + BehaviorEmotion + SexualAbuse + DomesticViolence > 1
update myTable set myField = 1 where 2 <= (select SubstanceAbuse + BehaviorEmotion + SexualAbuse + DomesticViolence from ...)
Of course, this is just a template for your query, but you get the idea. If the answer is still unclear then I kindly ask you to give me more details.
Best regards,
Lajos Arpad.

TSQL Summary by account, what is the cleanest way to approach this?

I am trying to total by account, the expenses & income per account. There are multiples of both the income & the expenses per account. I am struggling with this as am still learning SQL and thought that someone else likely has already addressed this? I sure would appreciate the help!
I know that this SQL server code is not correct but it at least gives a bit clearer picture of what I am attempting to do.
IF(SELECT(OBJECT_ID('TEMPDB..#Total'))) IS NOT NULL DROP TABLE #Total
declare #Expenses decimal(13,2),
#income decimal(13,2)
set #expenses = sum(EXP_CHILD_CARE_AMOUNT)
+ sum(EXP_FOOD_AMOUNT)
+ sum(EXP_LIFE_INSURANCE_AMOUNT)
+ sum(EXP_TRANSPORTATION_AMOUNT)
+ sum(EXP_TUITION_AMOUNT)
+ sum(EXP_USER_2_AMOUNT)
+ sum(EXP_USER_3_AMOUNT)
+ sum(EXP_UTILITIES_AMOUNT)
set #income = (sum(NET_PAY_AMOUNT)
+ sum(OTHER_INCOME_AMOUNT)
SELECT F.LOAN_NUMBER, #Income, #Expenses
INTO #Total
FROM OPENQUERY(SvrLink, '
SELECT F.Account, #Income, #Expenses
FROM finances F
inner join account a on(a.Account = f.Account)
where a.balance > 0
FETCH ONLY WITH UR ')
...ok, assuming that some fields are grouped into the same table (if not you'll just have to write the joins), you just need 1 query. (I wish all languages were as concise...)
#AccountId is your desired account id.
SELECT l.LOAN_NUMBER, l.AccountId,
(SELECT sum(EXP_CHILD_CARE_AMOUNT) + sum(EXP_FOOD_AMOUNT) +
sum(EXP_LIFE_INSURANCE_AMOUNT) + sum(EXP_TRANSPORTATION_AMOUNT) +
sum(EXP_TUITION_AMOUNT) + sum(EXP_USER_2_AMOUNT) +
sum(EXP_USER_3_AMOUNT) + sum(EXP_UTILITIES_AMOUNT)
as ExpenseTotal FROM Expenses_Guessing_The_Table_Name
WHERE AccountId = #AccountId) as ExpenseTotal,
(SELECT sum(NET_PAY_AMOUNT) + sum(OTHER_INCOME_AMOUNT) as IncomeTotal
FROM Income_Guessing_The_Table_Name
WHERE AccountId = #AccountId) as IncomeTotal
FROM Loans l
WHERE l.AccountId = #AccountId AND l.Balance > 0