Incorrect data when run as subquery - sql

I have a query that takes data about given media from a table it joins it with the user table
:
SELECT media.id, media.user_id,#rownum := #rownum + 1 AS position
INNER JOIN users
ON media.user_id = users.id
FROM media_table
ORDER BY media.distance ASC, media.media_likes_count DESC, media.media_views_count Desc;
This query produces a nice looking table as follows:
media_id, user_id, position
39199 , 3949 , 1
39299 , 3149 , 2
39359 , 3944 , 3
39369 , 3349 , 4
39379 , 3149 , 5
39389 , 3449 , 6
From this derived table, I want to get position of media_id = 39389.
However if I include that query in subquery like this:
Select position from (SELECT media.id, media.user_id,#rownum := #rownum + 1 AS position from
INNER JOIN users
ON media.user_id = users.id
FROM media_table
ORDER BY media.distance ASC, media.media_likes_count DESC, media.media_views_count Desc;)
where media_id = 39389
Then the columns 'shuffle' and 39389 does not have position 6 anymore.

Not withstanding the errors in your query, assuming those are just typos, perhaps you're issue is not initializing your user defined variable. This condensed version works for me:
select postition
from (
select yourresults.*, #rn:=#rn+1 postition
from yourresults
join (select #rn:= 0) t
order by media_id
) t
where media_id = 39389
SQL Fiddle Demo
While this does not work:
select postition
from (
select yourresults.*, #rn:=#rn+1 postition
from yourresults
order by media_id
) t
where media_id = 39389
More Fiddle

Related

Select minimum Seq Num by ID

Just trying to write a simple query to get the row (per VENDOR_ID) with the minimum CNTCT_SEQ_NUM where the CONTACT_NAME is not blank.
Here is what I have written:
SELECT VENDOR_ID, MIN(CNTCT_SEQ_NUM) AS CNTCT_SEQ_NUM , CONTACT_NAME
FROM PS_VENDOR_CNTCT
WHERE VENDOR_ID IN ('ERSUT', 'MOOREA')
AND CONTACT_NAME <> ''
GROUP BY CONTACT_NAME, VENDOR_ID
Current Results:
VENDOR_ID CNTCT_SEQ_NUM CONTACT_NAME
ERSUT 19 V Smith
ERSUT 4 T Peterman
ERSUT 2 I GANCE
ERSUT 8 R FISHER
MOOREA 2 S DALY
MOOREA 4 B SLAUTEN
MOOREA 1 N BLAKELY
Expected results would be:
VENDOR_ID CNTCT_SEQ_NUM CONTACT_NAME
ERSUT 2 I GANCE
MOOREA 1 N BLAKELY
Try this-
SELECT A.* FROM PS_VENDOR_CNTCT A
INNER JOIN
(
SELECT VENDOR_ID,MIN(CNTCT_SEQ_NUM) CNTCT_SEQ_NUM
FROM PS_VENDOR_CNTCT
GROUP BY VENDOR_ID
)B ON A.VENDOR_ID = B.VENDOR_ID
AND A.CNTCT_SEQ_NUM = B.CNTCT_SEQ_NUM
A correlated subquery solves this:
select vc.*
from PS_VENDOR_CNTCT vc
where vc.CNTCT_SEQ_NUM = (select min(vc2.CNTCT_SEQ_NUM)
from PS_VENDOR_CNTCT vc2
where vc2.VENDOR_ID = vc.VENDOR_ID and
vc2.CONTACT_NAME <> ''
);
For performance, you can try an index on (VENDOR_ID, CONTACT_NAME, CNTCT_SEQ_NUM). This covers the subquery, although all the index records will still need to be scanned.
Seems you do not need MIN(), but Window Analytic Function such as ROW_NUMBER()
SELECT DISTINCT Q.VENDOR_ID, Q.CONTACT_NAME, Q.CNTCT_SEQ_NUM
FROM
(
SELECT P.*,
ROW_NUMBER() OVER
(PARTITION BY VENDOR_ID ORDER BY CNTCT_SEQ_NUM) AS RN
FROM PS_VENDOR_CNTCT P
WHERE VENDOR_ID IN ('ERSUT', 'MOOREA')
AND CONTACT_NAME <> ''
) Q
WHERE Q.RN = 1

ORACLE SQL equivalent to given mysql query

Hi I am stuck on conerting this query from mysql to oracle as oracle create problems in subquery order by. Query is:
SELECT bt_charges.bt_setup_id, bt_setups.name, IFNULL(bt_charges.charges_for,'OPD') as charges_for_vals, bt_charges.nc_applicable,bt_charges.unit_value,bt_charges.taxtype_id, bt_charges.id, bt_charges.amount, bt_charges.effective_date
FROM bt_setups JOIN bt_charges ON ( bt_charges.bt_setup_id = bt_setups.id AND
bt_charges.id = (SELECT id
FROM bt_charges ilaba
WHERE IFNULL(ilaba.charges_for,'OPD') = IFNULL(bt_charges.charges_for,'OPD')
AND ilaba.bt_setup_id= bt_setups.id AND ilaba.effective_date <= '2014-11-10'
AND ilaba.insprovider_id IS NULL AND ilaba.deleted=0
ORDER BY ilaba.effective_date DESC, ilaba.date_entered DESC
LIMIT 1))
WHERE bt_setups.status='Active' AND bt_setups.deleted=0
AND bt_charges.insprovider_id IS NULL
ORDER BY bt_setups.name, charges_for ASC
Here, bt_setups ( name, description ) is service provided and
bt_charges (effective_date date, date_entered datetime, charger_for char, bt_setup_id foreign key(bt_setups), insprovider_id foreign key(insproviders) ) contains charges for service applicable from effective_date, insprovider wise
SELECT bc.bt_setup_id, bs.name,
NVL(bc.charges_for,'OPD') as charges_for_vals,
bc.nc_applicable, bc.unit_value, bc.taxtype_id,
bc.id, bc.amount, bc.effective_date
FROM bt_setups bs JOIN bt_charges bc ON ( bc.bt_setup_id = bs.id AND
bc.id = (SELECT id FROM
(SELECT ilaba.id, ilaba.bt_setup_id
FROM bt_charges ilaba
WHERE NVL(ilaba.charges_for,'OPD') = NVL(bc.charges_for,'OPD')
AND ilaba.effective_date <= TO_DATE('2014-11-10', 'YYYY-MM-DD')
AND ilaba.insprovider_id IS NULL AND ilaba.deleted=0
ORDER BY ilaba.effective_date DESC, ilaba.date_entered DESC)
WHERE bt_setup_id = bs.id AND ROWNUM = 1
))
WHERE bs.status='Active' AND bs.deleted=0
AND bc.insprovider_id IS NULL
ORDER BY bs.name, charges_for ASC;
IFNULL -> NVL
'2014-11-10' -> TO_DATE('2014-11-10', 'YYYY-MM-DD') - I suppose ilaba.effective_date has DATE type
LIMIT 1 -> order by in the subquery + rownum=1 in the parent query

Binary Search Query using SQL

I have a binary tree presented in a SQL Server 2014 table:
UserID ParentUserID Position
----------------------------
1 Null Null <-- ROOT
2 1 Left
3 1 Right <-- Last Right for ID=1 (CTE query return 3)
4 2 Left
5 4 Left
6 5 Left
7 6 Left <-- Last Left for ID=1 (CTE query return 6)
To get last left id and last right id I am using CTE query:
; with left_hand_recurse as
(
select UserID
, ParentUserID
, 1 as depth
from Table1 where ParentUserID is null
union all
select child.UserID
, child.ParentUserID
, parent.depth + 1
from left_hand_recurse parent
join Table1 child
on parent.UserID = child.ParentUserID
and position = 'Left'
)
select top 1 *
from left_hand_recurse
order by
depth desc
;
and
; with right_hand_recurse as
(
select UserID
, ParentUserID
, 1 as depth
from Table1 where ParentUserID is null
union all
select child.UserID
, child.ParentUserID
, parent.depth + 1
from right_hand_recurse parent
join Table1 child
on parent.UserID = child.ParentUserID
and position = 'Right'
)
select top 1 *
from right_hand_recurse
order by
depth desc
;
It is working fine. This way I can get the last UserID in left or right side for root (for ParentUserID == 1)
I need to modify the CTE query to get same result but for specific ParentUserID which I want pass as a parameter #ParentUserID.
How to achieve this goal?
Just change this line in each CTE:
from Table1 where ParentUserID is null
to:
from Table1 where ParentUserID = #ParentId

Complex 'order by' or maybe sorting issue

I have a table that looks like this
Group Recipe Priority
0 A 400
0 A 200
0 B 500
0 B 100
1 C 300
1 C 300
1 D 600
Importance is "Group" > "Priority" > "Recipe"
Group 0 has to go first.
Within Group 0, Priority 500 has to go first (since it has higher priority), but for the efficiency, all the recipe has to go first.
After sorting,
it should look like this
Group Recipe Priority
0 B 500
0 B 100
0 A 400
0 A 200
1 D 600
1 C 300
1 C 300
I have tried all different ways to do 'order by' but cannot find a correct way.
thank you for the help
The problem is subtle. You want to order not by priority, but by the maximum priority for a given group/recipe combination. That is, you want to keep all the recipes together based on this max priority.
The following does this:
select t.Group, t.Recipe, t.Priority,
max(priority) over (partition by t.group, t.recipe) as maxpriority
from tablename t
order by t.Group asc, 4 desc, t.Recipe, priority desc
In older versions of Oracle, prior to having analytic functions available, we would have returned the specified result set using a query something like this:
SELECT f.group
, f.recipe
, f.priority
FROM foo f
JOIN ( SELECT g.group
, g.recipe
, MAX(g.priority) AS max_priority
FROM foo g
GROUP BY g.group, g.recipe
) m
ON m.group = f.group AND m.recipe = f.recipe
ORDER BY f.group
, m.max_priority DESC
, f.recipe
, f.priority DESC
This approach works in other databases that don't have analytic functions, such as MySQL.
NOTE: The query above is not NULL-safe, in that the JOIN predicates will eliminate rows that have NULL values for the group or recipe columns. It could be made NULL-safe, but it complicates the SQL a bit.
SELECT f.group
, f.recipe
, f.priority
FROM foo f
JOIN ( SELECT g.group
, g.recipe
, MAX(g.priority) AS max_priority
FROM foo g
GROUP BY g.group, g.recipe
) m
ON (m.group = f.group OR COALESCE(m.group,f.group) IS NULL)
AND (m.recipe = f.recipe OR COALESCE(m.recipe,f.recipe) IS NULL)
ORDER BY f.group
, m.max_priority DESC
, f.recipe
, f.priority DESC
An equivalent result can also be obtained using a correlated subquery in the SELECT list, except that this result set contains an extra "max_priority" column in the result set.
SELECT f.group
, f.recipe
, f.priority
, (SELECT MAX(g.priority)
FROM foo g
WHERE (g.group = f.group OR COALESCE(g.group,f.group) IS NULL)
AND (g.recipe = f.recipe OR COALESCE(g.recipe,f.recipe) IS NULL)
) AS max_priority
FROM foo f
ORDER BY f.group
, 4 DESC
, f.recipe
, f.priority DESC
(I haven't tested whether that correlated subquery could be removed from the SELECT list and entirely moved to the ORDER BY clause. If that worked, we'd eliminate returning the extra column, but that query would look really, really odd.) The other option (to omit that extra column) is to wrap this query (as an inline view) in another query.
SELECT e.group
, e.recipe
, e.priority
FROM (
SELECT f.group
, f.recipe
, f.priority
, (SELECT MAX(g.priority)
FROM foo g
WHERE (g.group = f.group OR COALESCE(g.group,f.group) IS NULL)
AND (g.recipe = f.recipe OR COALESCE(g.recipe,f.recipe) IS NULL)
) AS max_priority
FROM foo f
) e
ORDER BY e.group
, e.max_priority DESC
, e.recipe
, e.priority DESC

SQL: Add all values from different rows

I have two SQL queries I want to combine into one. The first one selects all the IDs of the rows I need to add in the second one:
SELECT t.mp_id FROM t_mp AS t
JOIN t_mp_og USING (mp_id)
WHERE og_id = 2928
AND t.description = 'Energy'
The second one should add together the values from the rows returned by the first query. Up until now I've only been able to add several selects with a + in between them. For a dynamic query that adds all the rows returned by query one, I'd like to do something equivalent to "foreach(value from query1){ sum += value }" and return that sum.
SELECT(
(SELECT current_value FROM t_value_time WHERE mp_id = 29280001 AND time_id =
(SELECT time_id FROM t_time WHERE time_stamp =
(SELECT max(time_stamp) FROM v_value AS v WHERE time_stamp is not null AND mp_id = 29280001)))
+
(SELECT current_value FROM t_value_time WHERE mp_id = 29280015 AND time_id =
(SELECT time_id FROM t_time WHERE time_stamp =
(SELECT max(time_stamp) FROM v_value AS v WHERE time_stamp is not null AND mp_id = 29280015)))
+
(SELECT current_value FROM t_value_time WHERE mp_id = 29280022 AND time_id =
(SELECT time_id FROM t_time WHERE time_stamp =
(SELECT max(time_stamp) FROM v_value AS v WHERE time_stamp is not null AND mp_id = 29280022)))
);
My two problems: I don't know how to add all rows in a set, only the manual "+" way. I also don't know how to put the ID from the row into the SELECT getting the value. I've tried AS, but it seems to only work for tables, not single values.
Thanks for you help,
MrB
here is the edited query
select t.mp_id,sum(current_value)
from t_value_time t, t_time tim, v_value v
where
where t.mp_id = v.mp_id
and v.time_stamp is not null
and tim.time_stamp = MAX(v.time_stamp)
and t.time_id=tim.time_id
and t.mp_id in ( 29280001,29280015,29280022)
group by t.mp_id
use SUM() for aggregation
Have you tried SELECT Name, SUM(X) FROM Table GROUP BY Name
SELECT SUM(CURRENT_VALUE )
FROM
T_VALUE_TIME INNER JOIN T_TIME ON T_VALUE_TIME.TIME_ID=T_TIME.TIME_ID
JOIN V_VALUE ON T_TIME.TIME_STAMP=V_VALUE.TIME_STAMP
WHERE T_VALUE_TIME.MP_ID IN (SELECT t.mp_id FROM t_mp AS t JOIN t_mp_og USING (mp_id)
WHERE og_id = 2928
AND t.description = 'Energy' )
AND T_TIME.TIME_ID=(SELECT MAX(TIME_STAMP) FROM V_VALUE WHERE TIME_STAMP IS NOT NULL)
GROUP BY V_VALUE.MP_ID