Subquery with eloquent model in laravel 5 - sql

I have the following raw query:
select *
from (select * from settings order by priority desc) x
group by name
I would like to use a laravel 5 query builder instead but cant get the subquery to work. Is there a way to do this without using raw query's?
The table:
id - name - priority
1 1 1
2 1 2
3 2 1
In the above case It will return row 2 and 3 like I want to
I tried this query:
$settings = \App\Setting::where('user_id', Auth::id())->orWhere('tool_id', $id)->groupBy('name')->orderBy('priority', 'desc')->get();
But this will return row 1 and 3.

Can you use CTE expressions? RANK() would work:
WITH CTE AS
(
SELECT *, RANK() OVER(PARTITION BY name ORDER BY priority desc) AS RowRank
FROM settings
)
SELECT id, name, priority
FROM CTE c
WHERE c.RowRank = 1

Related

Add a number for duplicate values in posgresql

I've a query in MySQL and I'm looking for a query which can perform below operation using Posgres
MySQL Query :
update APT_ADHOC_DISH_SRC_TABLE_AAMIR_TCH3 a,
(
SELECT #row_number:=CASE WHEN #email=email THEN #row_number+1 ELSE 1 END AS row_number,
#email:=email AS email,id
FROM APT_ADHOC_DISH_SRC_TABLE_AAMIR_TCH3,
(SELECT #row_number:=0,#email:='') AS t
ORDER BY email
) b
set a.r_no=b.row_number where a.id=b.id
Output:
Email
Row Number
Aamir
1
Aamir
2
Aamir
3
Suresh
1
Suresh
2
Hafiz
1
WITH cte AS (
SELECT id, ROW_NUMBER() OVER (PARTITION BY email ORDER BY id) AS row_number
FROM APT_ADHOC_DISH_SRC_TABLE_AAMIR_TCH3
)
UPDATE APT_ADHOC_DISH_SRC_TABLE_AAMIR_TCH3
SET row_number = cte.row_number
FROM cte
WHERE APT_ADHOC_DISH_SRC_TABLE_AAMIR_TCH3.id = cte.id
https://www.db-fiddle.com/f/3RqNHRGFjkU74v33upyfhi/0

Unable to get dedupe records with rank

I am trying to dedupe my dataset using rank, but it is not assigning a different number to the second record. What am I doing wrong here?
with get_rank as (
select id, code, rank() over (partition by id order by z.rowid) as ranking
from mytable z
)
select *
from get_rank
where ranking = 1
and id = 72755
ID CODE RANKING
---------- ---- ----------
72755 M 1
72755 M 1
Use row_number():
with get_rank as (
select id, code,
row_number() over (partition by id order by z.rowid) as ranking
from mytable z
)
select *
from get_rank
where ranking = 1 and id = 72755;
It is guaranteed to return a different value for each row.

Selecting a column where another column is maximal

I guess this is a standard problem. But I could not find a proper solution yet.
I have three columns in table A:
ID ID_Version Var
1 1 A
1 2 A
1 3 X
1 4 D
2 1 B
2 2 Z
2 3 D
3 1 A
4 1 B
4 2 Q
4 3 Z
For every unique ID, I would like to isolate the Var-value that belongs to the maximal ID-Version.
For ID = 1 this would be D, for ID = 2 this would be D, for ID = 3 this would be A and for ID = 4 this would be Z.
I tried to use a group by statement but I cannot select Var-values when using the max-function on ID-Version and grouping by ID.
Does anyone have a clue how to write fast, effective code for this simple problem?
use row_number() analytic function :
select ID,Var from
(
select row_number() over (partition by id order by id_version desc) as rn,
t.*
from tab t
)
where rn = 1
or max(var) keep (dense_rank...)
select id, max(var) keep (dense_rank first order by id_version desc) as var
from tab
group by id
Demo
You could use ranking function:
SELECT *
FROM (SELECT tab.*, ROW_NUMBER() OVER(PARTITION BY ID ORDER BY ID_Version DESC) rn
FROM tab)
WHERE rn = 1
Oracle has the keep syntax, so you can also use aggregation:
select id, max(id_version) as id_version,
max(var) keep (dense_rank first order by id_version desc) as var
from a
group by id;
You could also use a simple join to do what you want, see below :
SELECT A.id, A.var FROM A
JOIN
(SELECT id, MAX(id_version) as id_version
FROM A
GROUP BY id) temp ON (temp.id = A.id AND temp.id_version = A.id_version)
Or you could also use a subquery like this :
SELECT a1.id, a1.var FROM A a1
WHERE a1.id_version = (SELECT MAX(id_version) FROM A a2 WHERE a2.id = a1.id)

Select MAX issue SQL

Scenario:
I have a table with order status, for example:
/ ORDER LOG NUMBER LOG CODE
1 1 1 Preparing
2 1 2 Prepared
3 1 3 Sent
4 2 1 Preparing
5 2 2 Prepared
6 3 1 Preparing
I've been looking for a way to select orders, where last log code is Prepared.
For example I want to see all ORDERS where last LOG CODE is Prepared (last log)
Oracle supports Windowed Aggregates:
select *
from
( select
ORDER
,LOG_NUMBER
,LOG_CODE
-- last log number for each order
,max(LOG_NUMBER) over (partition by ORDER) as maxnum
from mytable
) dt
where LOG_NUMBER = maxnum
and LOG_CODE = 'Prepared'
or
select *
from
( select
ORDER
,LOG_NUMBER
,LOG_CODE
-- youngest row gets row_number 1
,ROW_NUMBER() over (partition by ORDER order by LOG_NUMBER desc) as rn
from mytable
) dt
where rn = 1
and LOG_CODE = 'Prepared'
You can use the analytic function to do so
https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions070.htm
It should be something like:
SELECT order LAG(log_code, 1, 0) OVER (PARTITION BY order ORDER BY log_number) AS prev_code FROM orders
This will at least deliver you a resultset which has the last code information.
Instead of using an outer select you should be able to extend the query with
"having prev_code = 'Prepared'"
A pretty efficient way is to use correlated subqueries:
select t.*
from t
where t.lognumber = (select max(t2.lognumber) from t t2 where t.order = t2.order) and
t.logcode = 'Prepared';

Getting all fields from table filtered by MAX(Column1)

I have table with some data, for example
ID Specified TIN Value
----------------------
1 0 tin1 45
2 1 tin1 34
3 0 tin2 23
4 3 tin2 47
5 3 tin2 12
I need to get rows with all fields by MAX(Specified) column. And if I have few row with MAX column (in example ID 4 and 5) i must take last one (with ID 5)
finally the result must be
ID Specified TIN Value
-----------------------
2 1 tin1 34
5 3 tin2 12
This will give the desired result with using window function:
;with cte as(select *, row_number(partition by tin order by specified desc, id desc) as rn
from tablename)
select * from cte where rn = 1
Edit: Updated query after question edit.
Here is the fiddle
http://sqlfiddle.com/#!9/20e1b/1/0
SELECT * FROM TBL WHERE ID IN (
SELECT max(id) FROM
TBL WHERE SPECIFIED IN
(SELECT MAX(SPECIFIED) FROM TBL
GROUP BY TIN)
group by specified)
I am sure we can simplify it further, but this will work.
select * from tbl where id =(
SELECT MAX(ID) FROM
tbl where specified =(SELECT MAX(SPECIFIED) FROM tbl))
One method is to use window functions, row_number():
select t.*
from (select t.*, row_number() over (partition by tim
order by specified desc, id desc
) as seqnum
from t
) t
where seqnum = 1;
However, if you have an index on tin, specified id and on id, the most efficient method is:
select t.*
from t
where t.id = (select top 1 t2.id
from t t2
where t2.tin = t.tin
order by t2.specified desc, id desc
);
The reason this is better is that the index will be used for the subquery. Then the index will be used for the outer query as well. This is highly efficient. Although the index will be used for the window functions; the resulting execution plan probably requires scanning the entire table.