postgresql how to check by two columns from join - sql

There are some points and point_types with mark actual:
points
------
id point_type
------
1 1
2 1
3 2
point_types
------
id actual
------
1 true
2 false
Also there are directions:
directions
------
id point_from point_to
------
1 1 1
2 1 2
3 1 3
4 2 1
5 2 2
6 2 3
7 3 1
8 3 2
9 3 3
I need only directions with actual point_from and point_to:
id point_from point_to
------
1 1 1
2 1 2
4 2 1
5 2 2
Trying with:
SELECT d.id, d.point_from, d.point_to
FROM directions d
JOIN points p ON (d.point_from = p.id OR d.point_to = p.id)
JOIN point_types pt ON pt.id = p.TYPE AND pt.actual = TRUE
GROUP BY 1,2,3
but getting directions with actual point_from or actual point_to :
id point_from point_to
------
1 1 1
2 1 2
3 1 3
4 2 1
5 2 2
6 2 3
7 3 1
8 3 2

Use a CTE that returns all the ids of the not actual points and then with NOT EXISTS get only the directions that do not contain any of them:
WITH cte AS (
SELECT p.id
FROM points p INNER JOIN point_types pt
ON pt.id = p.point_type
WHERE pt.actual = false
)
SELECT d.*
FROM directions d
WHERE NOT EXISTS (SELECT * FROM cte c WHERE c.id IN (d.point_from, d.point_to));
See the demo.

Related

Unable to use LAG function

I need to update a table as :
ID | START_DATE | response| FINAL_TREND
1 14-10-2021 4
1 15-10-2021 3
1 16-10-2021 2
1 17-10-2021 2
1 18-10-2021 3
1 19-10-2021 2
OUTPUT AS:
ID | START_DATE | response| FINAL_TREND
1 14-10-2021 4 NULL
1 15-10-2021 3 4
1 16-10-2021 2 3
1 17-10-2021 2 2
1 18-10-2021 3 2
1 19-10-2021 2 3
So, when running a code:
SELECT LAG(RESPONSE,1) OVER (ORDER BY START_DATE) AS NEW
FROM DUMMY_YC
Output as:
NULL
4
3
2
3
2
2
But when using same code in update AS:
UPDATE DUMMY_YC A SET A.RESPONSE = (SELECT LAG(B.RESPONSE,1) OVER (ORDER BY B.START_DATE) AS NEW
FROM DUMMY_YC B WHERE B.START_DATE=A.START_DATE)
output as:
7 rows updated.
But the actual updated value is
RESPONSE|
(null)
(null)
(null)
(null)
(null)
(null)
(null)
Helps will be appreciated. Working On Oracle SQL Developer.
I'd go with merge.
Before:
SQL> SELECT *
2 FROM test
3 ORDER BY id, start_date;
ID START_DATE RESPONSE FINAL_TREND
---------- ---------- ---------- -----------
1 14.10.2021 4 0
1 15.10.2021 3 0
1 16.10.2021 2 0
1 17.10.2021 2 0
1 18.10.2021 3 0
1 19.10.2021 2 0
6 rows selected.
Merge:
SQL> MERGE INTO test a
2 USING (SELECT b.id,
3 b.start_date,
4 b.response,
5 LAG (b.response, 1) OVER (ORDER BY b.start_date) AS final_trend
6 FROM test b) x
7 ON ( x.id = a.id
8 AND x.start_date = a.start_date)
9 WHEN MATCHED
10 THEN
11 UPDATE SET a.final_trend = x.final_trend;
6 rows merged.
After:
SQL> SELECT *
2 FROM test
3 ORDER BY id, start_date;
ID START_DATE RESPONSE FINAL_TREND
---------- ---------- ---------- -----------
1 14.10.2021 4
1 15.10.2021 3 4
1 16.10.2021 2 3
1 17.10.2021 2 2
1 18.10.2021 3 2
1 19.10.2021 2 3
6 rows selected.
SQL>

Join multiple columns, filling non-existent values with 0

I have 2 tables, staff_product and orders_with_over_20k_product.
staff_product
STAFF_ID PRODUCT_ID
---------- ----------
2 6
2 4
2 5
2 7
1 6
1 4
1 5
1 7
3 6
3 4
3 5
3 7
orders_with_over_20k_product
STAFF_ID PRODUCT_ID PQ
---------- ---------- ----------
1 4 20
2 5 100
1 5 10
1 7 8
2 7 1
2 4 10
2 6 100
1 6 100
3 4 1
I want to join them such that if there is a record in staff_product that has matching values in orders_with_over_20k_product then PQ will be copied, and if there isn't then PQ will be set to 0. I also want to preserve the order or product_id in staff_product (it's important for how my program handles this query). The desired output is as follows
STAFF_ID PRODUCT_ID PQ
---------- ---------- ---------
2 6 100
2 4 10
2 5 100
2 7 1
1 6 100
1 4 20
1 5 10
1 7 8
3 6 0
3 4 1
3 5 0
3 7 0
I'll be executing this select in a stored procedure and both the existing tables are currently views made of different queries. How would construct a query for my desired output?
I think you just want a left join and coalesce():
select sp.*, coalesce(ow.pq, 0) as pq
from staff_product sp left join
orders_with_over_20k_product ow
on sp.staff_id = ow.staff_id and sp.product_id = ow.product_id
You can do a left join and coalesce():
select
p.*,
coalesce(o.pq, 0) pq
from staff_product p
left join orders_with_over_20k_product o
on o.product_id = p.product_id and o.staff_id = p.staff_id
Please use below SQL code for this issue.
SELECT A.STAFF_ID
,A.PRODUCT_ID
,coalesce(B.PQ, 0) AS PQ
FROM staff_product AS A
LEFT JOIN orders_with_over_20k_product AS B ON A.STAFF_ID = B.STAFF_ID
AND A.PRODUCT_ID = B.PRODUCT_ID

Select Command return Duplicate Rows

I have 3 tables:
Table 1 ExamTB:
ID ExamTerm ExamDate
1 MidTerm 2017-09-24
2 FinalTerm 2017-12-01
Table 2 ExamSubMarksTB
ID ExamID ClassID SubjectID TotalMarks PassMarks
1 1 1 1 100 50
2 1 1 2 100 50
3 1 1 3 100 50
4 2 1 1 100 50
5 2 1 2 100 50
6 2 1 3 100 50
Table 3 ExamResultTB
ID ExamID ClassID SubjectID MarksObtain StdID
1 1 1 1 80 1
2 1 1 2 70 1
3 1 1 3 60 1
4 2 1 1 50 1
5 2 1 2 72 1
6 2 1 3 68 1
Now when I create a Stored Procedure the SELECT this Select Command returns duplicate rows
SELECT ExamResultTB.ExamID
, ExamTB.ExamTerm
, ExamTB.ExamDate
, ExamResultTB.StdID
, StudentTB.Name
, StudentTB.FatherName
, ClassTB.ClassName
, SubjectTB.Subject
, ExamResultTB.ObtainMarks
, ExamSubMarksTB.TotalMarks
, ExamSubMarksTB.PassMarks
FROM ExamResultTB
INNER JOIN ExamTB ON ExamResultTB.ExamID = ExamTB.ID
INNER JOIN ClassTB ON ExamResultTB.ClassID = ClassTB.ID
INNER JOIN SubjectTB ON ExamResultTB.SubjectID = SubjectTB.ID
INNER JOIN StudentTB ON ExamResultTB.StdID = StudentTB.ID
INNER JOIN ExamSubMarksTB ON ExamResultTB.ExamID = ExamSubMarksTB.ExamID
WHERE ExamResultTB.ExamID = 4
AND ExamResultTB.StdID=1
For sure this line make a duplicate row:
INNER JOIN ExamSubMarksTB ON ExamResultTB.ExamID = ExamSubMarksTB.ExamID
You should do it in this way:
INNER JOIN ExamSubMarksTB ON ExamResultTB.ExamID = ExamSubMarksTB.ExamID and
ExamResultTB.ClassId = ExamSubMarksTB.ClassId and ExamResultTB.SubjectID =
ExamSubMarksTB.SubjectID

Group by clause with count() and where condition in subquery

Table : Class
id Institute_id Name
------------------------------
1 1 MCAL - 1
2 1 MCAL - 2
3 1 BCA - 1
4 1 BCA - 2
Table : Groups
id Class_Id Institute_Id Name Status
--------------------------------------------------
1 1 1 PHP false
2 2 1 JAVA false
3 1 1 ORACLE false
4 2 1 LINUX true
5 2 1 ASP.NET false
6 3 1 OS false
7 4 2 CPP false
Expected Result :
id Name Count(*)
-----------------------------
1 MCAL - 1 2
2 MCAL - 2 2
3 BCA - 1 1
4 BCA - 2 0
Note: count only those records from Groups where Institute_Id = 1 and Status=false
Please try this
Select
c.id,
c.name,
SUM(case when g.class_id is NULL then 0 else 1 end) as count
from class c left join groups g
on c.id=g.class_id
and g.status='false'
and g.Institute_id=1
group by c.id,c.name
order by c.id
fiddle link: http://sqlfiddle.com/#!6/2b992/6
To count properly with outer joins, specify the column name instead of * in COUNT().
SELECT C.id, C.Name, [Count] = COUNT(G.Status)
FROM Class C
LEFT JOIN Groups G ON C.id = G.Class_id AND G.Institute_id = 1 AND G.Status = 'false'
GROUP BY C.id, C.Name
ORDER BY C.id

Fetch the latest records from many-to-many relationship table

I am using SQL Server 2008 R2.
I am having three tables in my database are having many-to-many relationship as below.
TblServiceLevel
Id ServiceLevel Code
1 C 1
2 R 1
3 V 1
4 R Test 4
5 C Test 4
6 S 2
7 K 3
TblUser
Id Name
1 A
2 B
3 C
4 D
5 E
6 F
TblUserServiceLevel
Id UserId ServiceLevelId Status
1 1 1 Active
2 1 1 Deactive
3 2 3 Active
4 3 4 Active
5 1 5 Active
6 5 1 Active
7 2 3 Deactive
8 3 4 Deactive
9 5 1 Deactive
10 2 3 Active
11 3 4 Active
12 4 1 Active
Now,
From this tables, I want distinct users that are exists in TblUserServiceLevel and
having latest service level ="Active" and ServiceLevel.Code <> 4.
Can anyone help me?
The result is 2 and 4 user id.
select t1.UserId
from TblUserServiceLevel t1
inner join (
select UserId, max (Id) as maxId
from TblUserServiceLevel
group by UserId
) t2 on t1.UserId = t2.UserId and t1.Id = t2.maxId
inner join TblServiceLevel sl on t1.ServiceLevelId = sl.Id and sl.Code <> 4
where t1.Status = 'Active'