SQL Join on the same table - sql

Table T
P_ID | Name | Status
1 ABC Ordered
1 ABC Processing
1 ABC Imported
2 PQR Ordered
2 PQR Failed
3 LMN Ordered
Expected Result
Table T
P_ID | Name | Status
2 PQR Ordered
2 PQR Failed
3 LMN Ordered
I am not getting the correct result with the following query. I want to find all the records that have status Ordered but do not have the status "Imported".
select c1.P_ID,c1.Name,c2.Status
from T c1, T c2
where c1.P_ID = c2.P_ID
c1.Status="Ordered" and c2.status != "Imported"
Using Oracle 11g database

select c1.P_ID, c1.Name, c1.Status
from T c1
where c1.Status = 'Ordered' and
NOT EXISTS (SELECT 1
FROM T c2
WHERE c1.P_ID = c2.P_ID and c2.status = 'Imported'
);

You can use the following code:
select c1.P_ID,c1.Name,c1.Status
from T c1
where exists (select 1
from T
where P_ID = c1.P_ID
and Status="Ordered"
and rownum = 1)
and not exists (select 1
from T
where P_ID = c1.P_ID
and Status="Imported"
and rownum = 1)

Related

Insert rows for records that exists with a distinct id

I'd like to insert a row for each distinct id that exists in my table. What is the best and efficient practice to add these rows for each distinct id?
ID Name Count
-- ---- ---
A1 ABC 4
A1 BCD 2
B1 KLM 1
C2 STU 3
C2 BCD 1
C2 DEF 5
EXPECTED RESULT AFTER INSERT
ID Name Count
-- ---- ---
A1 ABC 4
A1 BCD 2
A1 EXISTS 1
B1 KLM 7
B1 EXISTS 1
C2 STU 3
C2 BCD 4
C2 DEF 5
C2 EXISTS 1
Use union all:
select id, name, count
from t
union all
select distinct id, 'EXISTS', 1
from t;
An insert is even simpler:
insert into t (id, name, count)
select distinct id, 'EXISTS', 1
from t;

How to do rows to column in SQL Server with count

How do I simply switch Rows with Column in SQL with count? Is there any way to do?
Actually i want against each unique mobile no with count and product name side by side means if two mobile no in table then count = 2 and side of that two product1,product2 shows in output.
ie turn this result:
Srno Name| Mobile| Count | ProductName
1 xyz 1234 1 LNM
2 PQR 5678 1 VCD
3 xyz 1234 1 KLM
4 PQR 5678 1 NMG
into this:
Srno Name| Mobile| Count | ProductName1 | ProductName2
1 xyz 1234 2 LNM KLM
2 PQR 5678 2 VCD NMG
If you have a limited products then you use row_number() & do conditional aggregation :
select min(srno) as srno, name, Mobile, count(*) as cnt,
max(case when seq = 1 then ProductName end) as ProductName1,
max(case when seq = 2 then ProductName end) as ProductName2
from (select t.*,
row_number() over (partition by name, Mobile order by srno) as seq
from table t
) t
group by name, Mobile;
Try this:
SET #row_number = 0;
SELECT
(#row_number:=#row_number + 1) AS Srno,
T1.name,
T1.Mobile,
SUM(T1.xCount + T2.xCount) as cnt,
max(T1.ProductName) as Product1,
max(T2.ProductName) as Product2
FROM Table1 as T1
LEFT JOIN Table1 AS T2 ON T1.name = T2.name
AND T2.srno > T1.srno
GROUP BY T1.name, T1.Mobile
ORDER BY Srno

Select from table based on the latest entry in another table in Oracle

I have a WHERE clause in a query that needs to see whether the latest entry in a related table meets certain criteria. However, I'm not able to inject the PK of the top query directly into the clause for a number of different reasons.
Is there any way to rewrite the following query to depend on the outer alias (ie. make ALIAS.pk work)? foo has a composite primary key.
(SELECT CASE WHEN EXISTS (
SELECT * FROM (
SELECT n.val1, n.val2 FROM (
SELECT * FROM foo f
WHERE f.val0 = 100 AND f.outerid = ALIAS.pk
ORDER BY f.date DESC
) n
WHERE n.rownum = 1
) t
WHERE t.val1 = 1 AND t.val2 = 2
) THEN 1 ELSE 0 END FROM dual) = 1
Edit: Outer table (bar):
id name city
1 Bob London
2 Mike Atlanta
3 Susan Toronto
Inner table (foo):
outerid date val1 val2 val100 fk1 fk2 fk3
1 2014-11-11 1 2 100 11 523 15
1 2014-11-11 1 2 101 14 12 87
1 2014-11-10 1 2 100 17 1667 12
2 2014-11-11 1 1 100 91 12 188
The primary key for foo is a composite key over fk1..3.
So what I need is to select the latest entry from foo that corresponds to a certain user and check that it has certain characteristics.
Edit 2:
SELECT CASE WHEN ({inner query})=1 THEN 1 ELSE 0 END WHERE id = 1 should return "1" SELECT SELECT CASE WHEN ({inner query})=1 THEN 1 ELSE 0 END WHERE id = 2 should return "0".
This may give you the output you require:
SELECT b.name
FROM bar b
INNER JOIN
(SELECT DISTINCT
f.outerid
FROM
(SELECT f.outerid
, f.val1
, f.val2
, f.date
, max(f.date) OVER
(PARTITION BY f.outerid
ORDER BY f.date) max_date
FROM foo f
WHERE f.val0 = 100) f
WHERE f.date = f.max_date
AND f.val1 = 1
AND f.val2 = 2) f
ON (f.outerid = b.id)

How to Add Order to an existing table?

I have table called Products. Let say this is my table,
ID Name ParentID
-- --- --------
1 a NULL
2 b NULL
3 a1 1
4 a2 1
5 b2 2
6 b2 2
Now I need to add [Order] Column with respect to ParentID,
ID Name ParentID Order
-- --- -------- ----
1 a NULL NULL
2 b NULL NULL
3 a1 1 1
4 a2 1 2
5 b2 2 1
6 b2 2 2
Creating [Order] is trivial but inserting record is a bit tricky part
UPDATE [Products]
SET [Products].[Order] = PTT.[Order]
FROM
[Products]
INNER JOIN (SELECT ID, ROW_NUMBER() OVER (PARTITION BY PT.ParentID ORDER BY ID) AS [Order]
FROM [Products] PT
WHERE PT.ParentID IS NOT NULL) AS PTT ON PTT.ID = [Products].ID

Get the max value of a column from set of rows

I have a table like this
Table A:
Id Count
1 4
1 16
1 8
2 10
2 15
3 18
etc
Table B:
1 sample1.file
2 sample2.file
3 sample3.file
TABLE C:
Count fileNumber
16 1234
4 2345
15 3456
18 4567
and so on...
What I want is this
1 sample1.file 1234
2 sample2.file 3456
3 sample3.file 4567
To get the max value from table A I used
Select MAX (Count) from A where Id='1'
This works well but my problem is when combining data with another table.
When I join Table B and Table A, I need to get the MAX for all Ids and in my query I dont know what Id is.
This is my query
SELECT B.*,C.*
JOIN A on A.Id = B.ID
JOIN C on A.id = B.ID
WHERE (SELECT MAX(COUNT)
FROM A
WHERE Id = <what goes here????>)
To summarise, what I want is Values from Table B, FileNumber from Table c (where the count is Max for ID from table A).
UPDATE: COrrecting table C above. Looks like I need Table A.
I think this is the query you're looking for:
select b.*, c.filenumber from b
join (
select id, max(count) as count from a
group by id
) as NewA on b.id = NewA.id
join c on NewA.count = c.count
However, you should take into account that I don't get why for id=1 in tableA you choose the 16 to match against table C (which is the max) and for id=2 in tableA you choose the 10 to match against table C (which is the min). I assumed you meant the max in both cases.
Edit:
I see you've updated tableA data. The query results in this, given the previous data:
+----+---------------+------------+
| ID | FILENAME | FILENUMBER |
+----+---------------+------------+
| 1 | sample1.file | 1234 |
| 2 | sample2.file | 3456 |
| 3 | sample3.file | 4567 |
+----+---------------+------------+
Here is a working example
Using Mosty’s working example (renaming the keyword count to cnt for a column name), this is another approach:
with abc as (
select
a.id,
a.cnt,
rank() over (
partition by a.id
order by cnt desc
) as rk,
b.filename
from a join b on a.id = b.id
)
select
abc.id, abc.filename, c.filenumber
from abc join c
on c.cnt = abc.cnt
where rk = 1;
select
PreMax.ID,
B.FileName,
C2.FileNumber
from
( select C.id, max( C.count ) maxPerID
from TableC C
group by C.ID
order by C.ID ) PreMax
JOIN TableC C2
on PreMax.ID = C2.ID
AND PreMax.maxPerID = C2.Count
JOIN TableB B
on PreMax.ID = B.ID