Get the last row in Slick - sql

I have PostgreSQL table.
Messages:
|id | phone | message | login |
-----------------------------------
* |1 | 85543422 | Hello! | User1 |
|2 | 85543422 | i love | User2 |
-----------------------------------*
I need to filter the table by phone value (85543422) and get the username from the last row.
Now I have a method that allows you to pull the username from the first line.
//return "User1"
def getUserByPhone():String = {
val query = outgoing.filter(_.phone === "85543422").map(_.login).result.headOption
val result = Await.result(db.run(query), Duration.Inf)
if (result.value.isEmpty) return "None"
result.value.get
}
Help with the implementation of the method for removing the user name from the last line.
I need get "User2"

You may sort by id desc to get the username on the last row
eg
val query = outgoing.filter(_.phone === "85543422")
.sortBy(_.id.desc)
.map(_.login).result.headOption

Related

Combine KQL Queries into a single query

I have two separate KQL queries I'm using on Azure Log analytics to find blocks on an Azure WAF, the first one finds the transactionid or requests that were blocked.
//Query 1
AzureDiagnostics
| where ResourceType == "APPLICATIONGATEWAYS" and OperationName == "ApplicationGatewayFirewall"
| where hostname_s in ('www.website.com')
| where Message !startswith "Mandatory"
| where action_s in ('Blocked', 'Detected')
| project transactionId_g
To find all the parts of the request that combine to generate the block I then copy/paste the transactionid's to a 2nd query and that all requests that are part of that transaction which gives me the data I need to create exceptions on the WAF if it's a false positive.
//Query 2
AzureDiagnostics
| where ResourceType == "APPLICATIONGATEWAYS" and OperationName == "ApplicationGatewayFirewall"
| where Message !startswith "Mandatory"
| where transactionId_g == "8eb316fd-4a5b-66c7-0136-fc67e21d282b"
| project transactionId_g, TimeGenerated, clientIp_s, hostname_s, requestUri_s, ruleId_s, ruleSetVersion_s, ruleGroup_s, action_s, Message, details_message_s, details_data_s
| sort by transactionId_g
Is there a way to combine these two queries together into a single query that finds the transactionid's of blocked requests, then shows ALL log lines containing those transactionid's?
if there's a single transaction ID returned by the 1st query, you could use the toscalar() function:
let tid = toscalar(
AzureDiagnostics
| where ResourceType == "APPLICATIONGATEWAYS" and OperationName ==
"ApplicationGatewayFirewall"
| where hostname_s in ('www.website.com')
| where action_s in ('Blocked', 'Detected')
| where Message !startswith "Mandatory"
| project transactionId_g
| take 1
);
AzureDiagnostics
| where transactionId_g == tid // <-- this is where you use the result of the 1st subquery
| where ResourceType == "APPLICATIONGATEWAYS" and OperationName == "ApplicationGatewayFirewall"
| where Message !startswith "Mandatory"
| project transactionId_g, TimeGenerated, clientIp_s, hostname_s, requestUri_s, ruleId_s, ruleSetVersion_s, ruleGroup_s, action_s, Message, details_message_s, details_data_s
| sort by transactionId_g
or, if the first query returns a set of transaction IDs and not a single one, you could use the in operator:
let tids =
AzureDiagnostics
| where ResourceType == "APPLICATIONGATEWAYS" and OperationName ==
"ApplicationGatewayFirewall"
| where hostname_s in ('www.website.com')
| where action_s in ('Blocked', 'Detected')
| where Message !startswith "Mandatory"
| project transactionId_g
;
AzureDiagnostics
| where transactionId_g in (tids) // <-- this is where you use the result of the 1st subquery
| where ResourceType == "APPLICATIONGATEWAYS" and OperationName == "ApplicationGatewayFirewall"
| where Message !startswith "Mandatory"
| project transactionId_g, TimeGenerated, clientIp_s, hostname_s, requestUri_s, ruleId_s, ruleSetVersion_s, ruleGroup_s, action_s, Message, details_message_s, details_data_s
| sort by transactionId_g

Implementing Two Level Aggregate in PostgreSQL using Sequelize Function for NodeJS App

Hello guys please bear with me here. I'm using PostgreSQL, Sequelize, Express, and NodeJS to create a backend. I'm wondering if these lines of raw query code can be implemented using Sequelize Model findAll function.
First of all, what I am trying to do here is to calculate the total score of these students. Here are some tables and their relations.
Student Level
| student_id | name | level_id | | level_id | level_name |
|:----------:|:----------:|:--------:| |:--------:|:----------:|
| 1 | John | 1 | > | 1 | Rookie |
| 2 | Jane | 2 | | 2 | Expert |
v
StudentQuiz
| quiz_id | student_id | score |
|:----------:|:----------:|:--------:|
| 1 | 1 | 40 |
| 1 | 1 | 100 |
| 2 | 1 | 80 |
| 1 | 2 | 100 |
| 2 | 2 | 100 |
If I run line of codes below.
SELECT table2.student_id,
s.canvasser_name,
l.level_name,
table2.total_score
FROM (SELECT table1.student_id,
sum(table1.max_score) total_score
FROM (SELECT sq.student_id,
max(sq.score) max_score
FROM public.StudentQuiz sq
GROUP BY sq.quiz_id, sq.student_id) table1
GROUP BY table1.student_id) table2
INNER JOIN public.Student s
ON s.student_id = table2.student_id
INNER JOIN public.Level l
ON l.level_id = s.level_id
ORDER BY table2.total_score DESC
LIMIT 10;
I will get something like this.
| student_id | name | level | total_score |
|:----------:|:----------:|:--------:|:--------------:|
| 1 | John | Rookie | 180 |
| 2 | Jane | Expert | 200 |
Please note that I'm selecting the highest score if more than one quiz with the same id found.
Anyway, I want to implement it using sequelize built in function. What I've been trying to do is something like this.
const result = await StudentQuiz.findAll({
attributes: ['studentId', [sequelize.fn('sum', sequelize.fn('max', sequelize.col('score'))), 'totalPrice'], 'quizId'],
group: 'studentId',
include: [
{
model: Student,
include: [{
model: Level
}],
},
],
offset: 0,
limit: 10
});
The code above throws an error message which is "aggregate function calls cannot be nested".
Any kind of help will be appreciated. Thank you.
P.S. I know i can use sequelize.query() function to use the first code block shown, but that's not the point.
Sequelize is not intended to work with complex aggregations using models. Its primary goal is to provide CRUD operations with models.
To use models in such scenario you can use a model definition to get a schema, a table name and fields to build a query dynamically not knowing exact field names.
I find the solution without using any raw query, though I need to get two tables, that is StudentQuiz and Student that coupled by Level. Here is my answer.
// Finding maximum score and group it based on studentId and quizId
const maxScoreList = await StudentQuiz.findAll({
attributes: ['studentId', 'quizId', [sequelize.fn('max', sequelize.col('score')), 'maxScore']],
group: ['studentId', 'quizId'],
order: ['studentId', 'quizId'],
raw: true
});
// Calculating total score for the same student for each quiz recorded
const scoreArray = [maxScoreList.shift()];
let index = 0;
const unfilteredStudentId = maxScoreList.map((item) => {
if (scoreArray[index].studentId !== item.studentId) {
scoreArray.push(item);
index += 1;
}
scoreArray[index].maxScore += item.maxScore;
return item.studentId;
});
// Filtering studentId that show up more than one time
const extractedStudentId = [...new Set(unfilteredStudentId)];
// Finding student based on studentId inside extractedStudentId array
const student = await Student.findAll({
where: { id: extractedStudentId },
attributes: ['id', 'canvasserId', 'canvasserName', 'canvasserImageUrl'],
include: {
model: Level,
attributes: [['level_name', 'level'], ['icon_url', 'level_image_url']]
},
order: ['id'],
raw: true,
nest: true
});
// Combining total score list to student list
const rankList = student.map((item, idx) => ({ ...item, totalScore: scoreArray[idx] }));
With this much complexity, I agree that using raw query by far the best approach for this case.

Condition with SQL

I've come to see you for a question. Is there a condition in SQL that allows you to do that:
IF(sup = void) {
}
Database
id | name | lastname | city | mail | number | picture | ...
1 | kiwi | kiwi | USA | kiwi#gmail.com | 0000000000 | default.img | (vide)
SELECT * FROM your_table WHERE sup IS NULL
https://www.w3schools.com/sql/sql_null_values.asp
Update after reading your comment.
$test = $db->query("SELECT * FROM ressource_view WHERE ID = 1")
Will give you the result of your query. Be careful as there could be multiple rows returned.
To fetch the first row
$row = $result->fetch_array()
And then to check if the sup column of your row is null you can use:
if(is_null($row['sup']))
{
}
Or this will have the same effect
if($row['sup'] === NULL)
{
}
But best to tag your question with PHP, MySQL. Your problem seems to be more on the PHP side and someone else could provide a better answer.

tell me the sql

I have a table like this.
Table name : message
mid | mfrom | mto | msg
------------------------
1 | a | b | hi
2 | b | a | hello
3 | a | c | how are you
4 | c | a | fine
i am able to show all rows by
`$sql = mysql_query("SELECT *
FROM message
WHERE mto = '$to'
OR mfrom = '$to';");
while($row = mysql_fetch_array($sql))
{
echo $row['msg'];
}`
but i want to show only one result if mfrom and mto or mto and mfrom is equal. Such as if mfrom =a and mto=b or mfrom=b and mto=a. I want to show only one result from them like this
mid | mfrom | mto | msg
-------------------------
2 | b | a | hello
4 | c | a | fine
please tell me the query.
Your question is not clear because your "query" seems wrong ("mfrom and mto or mto and mfrom is equal" doesn't seem correct).
Nevertheless, as you named the table "message", I'm guessing that you want each message once even though it appears twice in the table.
What you could do is query from the table "twice" and then use the bigger of the ids:
SELECT first.* FROM message AS first LEFT JOIN message AS second
ON first.mfrom = second.mto AND first.mto = second.mfrom
WHERE first.mid > second.mid OR second.mid is NULL;
This would give you the result you requested. It would also give you any message that doesn't have a "partner" row.
If you want only matching messages, you can remove the "OR second.mid is NULL".

Combining two identically-structured tables where one has priority, and also excluding by field value

I have two tables, like this:
t_Normal
----------------------------------------------
FieldKey | FieldLabel | FieldValue
----------------------------------------------
greet_hw | Hello, world! | HELLOWORLD
----------------------------------------------
greet_ws | What's shakin? | WHATISSHAKING
----------------------------------------------
greet_hh | How's it hangin?| HOWDOESITHANG
----------------------------------------------
t_Override
------------------------------------------------------------
FieldKey | FieldLabel | FieldValue | FieldStatus
------------------------------------------------------------
greet_ws | What's shakin? | WHATISSHAKING | Retired
------------------------------------------------------------
greet_s | Sup!?!?? | SUPELEVEN | Active
------------------------------------------------------------
greet_hh | How swings it? | HOWDOESITHANG | Active
------------------------------------------------------------
Can I join them in a view to get this:
v_FieldMaster
---------------------------------------------
FieldKey | FieldLabel | FieldValue
---------------------------------------------
greet_hw | Hello, world! | HELLOWORLD
---------------------------------------------
greet_s | Sup!?!?? | SUPELEVEN
---------------------------------------------
greet_hh | How swings it? | HOWDOESITHANG
---------------------------------------------
So it's joined to produce v_FieldMaster like this:
Any totally different table rows (where comparison is made based on a combination of FieldKey and FieldValue) are included. E.g. Hello, world! only appears in t_Normal, and Sup!?!?? only appears in t_Override.
Any rows that match based on Name and Value take the t_Override table's Label field. E.g. How swings it? instead of How's it hangin?
Any rows that appear in both (or just t_Override) , but are set as Status=Retired in t_Override, do not appear. E.g. What's shakin'? doesn't appear.
Quickest way to combine two identical structured tables without duplicate entries has got me part of the way there, but I haven't yet figured out how to combine that technique with a where clause matching on t_Override.FieldStatus. Any suggestions very welcome!
Do a full join, but only select the rows where there is either no override or the override is 'Active'. Coalesce each field to prioritize the override values if they are there.
SELECT
COALESCE(o.FieldKey ,n.FieldKey ) AS FieldKey ,
COALESCE(o.FieldLabel ,n.FieldLabel ) AS FieldLabel ,
COALESCE(o.FieldStatus,n.FieldStatus) AS FieldStatus
FROM t_Normal n
FULL JOIN t_Override o ON (o.FieldKey = n.FieldKey)
WHERE (o.FieldKey IS NULL OR o.FieldStatus = 'Active')