Select min value from Tables using (sub Select ) - sql

I am trying to select a specific row from the tables. All are good, but the last select min is not working. So I need the min Leg Number after I make the whole selection.
SELECT cashier.* , legs.* ,cashier.id as cashier,
cashier.cashierNumber as cashierNum ,cashier.fullName as cashier
FROM myTable
INNER JOIN legs ON main.main= legs.legMain
INNER JOIN cashier ON legs.cashier = cashier.id
WHERE legs.RRZZFrom ='RR'
AND legs.LegNumber = (SELECT Min(legs.LegNumber) FROM legs)

where legs.RRZZFrom ='RR' and legs.LegNumber in (select min(legs.LegNumber) from legs)

you might want to try using cte.
with cte as (
select min(LegNumber) as minLegNum from legs
)SELECT cashier.* , legs.* ,cashier.id as cashier,
cashier.cashierNumber as cashierNum ,cashier.fullName as cashier
FROM myTable
INNER JOIN legs ON main.main= legs.legMain
INNER JOIN cashier ON legs.cashier = cashier.id
INNER JOIN cte c on c.minLegNum = legs.LegNumber
WHERE legs.RRZZFrom ='RR'

Are you looking for the MIN leg number only from the selected data? In that case, something like this:
WITH Details
AS
(
SELECT cashier.* , legs.* ,cashier.id as cashier,
cashier.cashierNumber as cashierNum ,cashier.fullName as cashier
FROM myTable
INNER JOIN legs ON main.main= legs.legMain
INNER JOIN cashier ON legs.cashier = cashier.id
WHERE legs.RRZZFrom ='RR'
)
SELECT d.*
FROM Details AS d
WHERE d.LegNumber = (SELECT MIN(d2.LegNumber) FROM Details AS d2);
Not sure if you'd need to alias any other columns there, as I don't know the table layout.

Try this:
WITH DataSource AS
(
SELECT cashier.*
,legs.*
,cashier.id as cashier
,cashier.cashierNumber as cashierNum
,cashier.fullName as cashier
,MIN(legs.LegNumber) OVER() AS [MinLegNUmber]
FROM myTable
INNER JOIN legs
ON main.main= legs.legMain
INNER JOIN cashier
ON legs.cashier = cashier.id
WHERE legs.RRZZFrom ='RR'
)
SELECT *
FROM DataSource
WHERE LegNumber = [MinLegNUmber];
The idea is to use a OVER() clause to calculate the minimum value after the selection for each row:
MIN(legs.LegNumber) OVER()
Then in outer query to return only the rows which are matching this value.
The OVER clause is particular powerful syntax which allows to perform operations (ranking, aggregations) over given set of values. The OVER() syntax means the whole entity.

Related

How to get records with distinct column value from result set in oracle?

could you please help me on the below query?
Using the query
SELECT LineGernal.Id, LineGernal.Description, LineGernal.SSMS, BaseAddOns.Id
from LineGernal Inner Join
BaseAddOns
on LineGernal.Id=BaseAddOns.ParentLineGernalID
Output-
Result Needed-
Thanks
Rajendra
You can use group by and min as follows:
SELECT LineGernal.Id, LineGernal.Description, LineGernal.SSMS, min(BaseAddOns.Id) as id
from LineGernal Inner Join
BaseAddOns
on LineGernal.Id=BaseAddOns.ParentLineGernalID
GROUO BY LineGernal.Id, LineGernal.Description, LineGernal.SSMS
I would recommend pre-aggregation in a subquery:
select li.id as lineGeneralId, lg.description, lg.ssms, bao.id as BaseAddOnsId
from LineGernal lg
inner join (
select ParentLineGernalID, min(id) as id
from BaseAddOns
group by ParentLineGernalID,
) bao on lg.id = bao.ParentLineGernalID

How select from query inside case in select

I have following query
SELECT DISTINCT v.id,
( CASE
WHEN date IS NULL THEN v.o_id
ELSE (SELECT os
FROM (SELECT o_id1 os
FROM tablet t2
WHERE t2.vso_id = v.id
ORDER BY date ASC)
WHERE rownum = 1)
END ) AS p_o,
v.o_id AS k_o
FROM tablev v
LEFT JOIN tablet t
ON v.id = t.v_id;
Here is what I need:
TableV has distinct v.id values. I need join that table with another (tableT) which has many records for same v.id and then for each distinct v.id:
select O_ID from V
if record for v.id in tableT does not exists(date is null) then
select O_ID from V (same as above)else select o_id1 from T with
minimum date
Also, aditional, is if possible to join o_id from 1. and o_id/o_id1 from2 to another table and write person's name?
I would like, instead of o_id, for each v.id to join selected o_id to another table(tableO) and select name.
So, I need these columns in result: V.id, p_o, k_o
But it would be really great if it looks like: v.id, p_o.name, k_o.name
To answer your first question, assuming that t.vso_id and t.v_id are the same thing (otherwise I might have misunderstood your question), try this query (I use another DBMS, so you might need to adjust the call to COALESCE a little):
SELECT v.id, COALESCE(t.o_id1, v.o_id), v.o_id
FROM tableV v
LEFT JOIN (
(SELECT vso_id, min(date) AS min_date FROM tableT GROUP BY vso_id) min_dates
JOIN tableT t
ON min_dates.vso_id = t.vso_id AND min_dates.min_date = t.date
) ON v.id = t.v_id;
Here's a breakdown:
(SELECT vso_id, min(date) AS min_date FROM tableT GROUP BY vso_id) AS min_dates
selects a smallest date for each vso_id.
(SELECT vso_id, min(date) AS min_date FROM tableT GROUP BY vso_id) AS min_dates
JOIN tableT t
ON min_dates.vso_id = t.vso_id AND min_dates.min_date = t.date
selects one row per vso_id, and that row will correspond to the smallest date that that vso_id has.
Finally, I join tableV to that query. COALESCE(t.o_id1, v.o_id) will return t.o_id if it is not NULL, v.o_id otherwise. You can use CASE instead, but I find COALESCE to be a better fit for this particular purpose.
To answer your second question, you can then JOIN against the table with names like this:
JOIN table_with_names twn1 ON twn1.id = COALESCE(t.o_id1, v.o_id)
JOIN table_with_names twn2 ON twn2.id = v.o_id
and project twn1.name and twn2.name.

SQL Group By Clause and Empty Entries

I have a SQL Server 2005 query that I'm trying to assemble right now but I am having some difficulties.
I have a group by clause based on 5 columns: Project, Area, Name, User, Engineer.
Engineer is coming from another table and is a one to many relationship
WITH TempCTE
AS (
SELECT htce.HardwareProjectID AS ProjectId
,area.AreaId AS Area
,hs.NAME AS 'Status'
,COUNT(*) AS Amount
,MAX(htce.DateEdited) AS DateModified
,UserEditing AS LastModifiedName
,Engineer
,ROW_NUMBER() OVER (
PARTITION BY htce.HardwareProjectID
,area.AreaId
,hs.NAME
,htce.UserEditing ORDER BY htce.HardwareProjectID
,Engineer DESC
) AS row
FROM HardwareTestCase_Execution AS htce
INNER JOIN HardwareTestCase AS htc ON htce.HardwareTestCaseID = htc.HardwareTestCaseID
INNER JOIN HardwareTestGroup AS htg ON htc.HardwareTestGroupID = htg.HardwareTestGroupId
INNER JOIN Block AS b ON b.BlockId = htg.BlockId
INNER JOIN Area ON b.AreaId = Area.AreaId
INNER JOIN HardwareStatus AS hs ON htce.HardwareStatusID = hs.HardwareStatusId
INNER JOIN j_Project_Testcase AS jptc ON htce.HardwareProjectID = jptc.HardwareProjectId AND htce.HardwareTestCaseID = jptc.TestcaseId
WHERE (htce.DateEdited > #LastDateModified)
GROUP BY htce.HardwareProjectID
,area.AreaId
,hs.NAME
,htce.UserEditing
,jptc.Engineer
)
The gist of what I want is to be able to deal with empty Engineer columns. I don't want this column to have a blank second entry (where row=2).
What I want to do:
Group the items with "row" value of 1 & 2 together.
Select the Engineer that isn't empty.
Do not deselect engineers where there is not a matching row=2.
I've tried a series of joins to try and make things work. No luck so far.
Use j_Project_Testcase PIVOT( MAX(Engineer) for Row in ( [1], [2] ) then select ISNULL( [1],[2]) to select the Engineer value
I can give you a more robust example if you set up a SQL fiddle
Try reading this: PIVOT and UNPIVOT

Limit join to one row

I have the following query:
SELECT sum((select count(*) as itemCount) * "SalesOrderItems"."price") as amount, 'rma' as
"creditType", "Clients"."company" as "client", "Clients".id as "ClientId", "Rmas".*
FROM "Rmas" JOIN "EsnsRmas" on("EsnsRmas"."RmaId" = "Rmas"."id")
JOIN "Esns" on ("Esns".id = "EsnsRmas"."EsnId")
JOIN "EsnsSalesOrderItems" on("EsnsSalesOrderItems"."EsnId" = "Esns"."id" )
JOIN "SalesOrderItems" on("SalesOrderItems"."id" = "EsnsSalesOrderItems"."SalesOrderItemId")
JOIN "Clients" on("Clients"."id" = "Rmas"."ClientId" )
WHERE "Rmas"."credited"=false AND "Rmas"."verifyStatus" IS NOT null
GROUP BY "Clients".id, "Rmas".id;
The problem is that the table "EsnsSalesOrderItems" can have the same EsnId in different entries. I want to restrict the query to only pull the last entry in "EsnsSalesOrderItems" that has the same "EsnId".
By "last" entry I mean the following:
The one that appears last in the table "EsnsSalesOrderItems". So for example if "EsnsSalesOrderItems" has two entries with "EsnId" = 6 and "createdAt" = '2012-06-19' and '2012-07-19' respectively it should only give me the entry from '2012-07-19'.
SELECT (count(*) * sum(s."price")) AS amount
, 'rma' AS "creditType"
, c."company" AS "client"
, c.id AS "ClientId"
, r.*
FROM "Rmas" r
JOIN "EsnsRmas" er ON er."RmaId" = r."id"
JOIN "Esns" e ON e.id = er."EsnId"
JOIN (
SELECT DISTINCT ON ("EsnId") *
FROM "EsnsSalesOrderItems"
ORDER BY "EsnId", "createdAt" DESC
) es ON es."EsnId" = e."id"
JOIN "SalesOrderItems" s ON s."id" = es."SalesOrderItemId"
JOIN "Clients" c ON c."id" = r."ClientId"
WHERE r."credited" = FALSE
AND r."verifyStatus" IS NOT NULL
GROUP BY c.id, r.id;
Your query in the question has an illegal aggregate over another aggregate:
sum((select count(*) as itemCount) * "SalesOrderItems"."price") as amount
Simplified and converted to legal syntax:
(count(*) * sum(s."price")) AS amount
But do you really want to multiply with the count per group?
I retrieve the the single row per group in "EsnsSalesOrderItems" with DISTINCT ON. Detailed explanation:
Select first row in each GROUP BY group?
I also added table aliases and formatting to make the query easier to parse for human eyes. If you could avoid camel case you could get rid of all the double quotes clouding the view.
Something like:
join (
select "EsnId",
row_number() over (partition by "EsnId" order by "createdAt" desc) as rn
from "EsnsSalesOrderItems"
) t ON t."EsnId" = "Esns"."id" and rn = 1
this will select the latest "EsnId" from "EsnsSalesOrderItems" based on the column creation_date. As you didn't post the structure of your tables, I had to "invent" a column name. You can use any column that allows you to define an order on the rows that suits you.
But remember the concept of the "last row" is only valid if you specifiy an order or the rows. A table as such is not ordered, nor is the result of a query unless you specify an order by
Necromancing because the answers are outdated.
Take advantage of the LATERAL keyword introduced in PG 9.3
left | right | inner JOIN LATERAL
I'll explain with an example:
Assuming you have a table "Contacts".
Now contacts have organisational units.
They can have one OU at a point in time, but N OUs at N points in time.
Now, if you have to query contacts and OU in a time period (not a reporting date, but a date range), you could N-fold increase the record count if you just did a left join.
So, to display the OU, you need to just join the first OU for each contact (where what shall be first is an arbitrary criterion - when taking the last value, for example, that is just another way of saying the first value when sorted by descending date order).
In SQL-server, you would use cross-apply (or rather OUTER APPLY since we need a left join), which will invoke a table-valued function on each row it has to join.
SELECT * FROM T_Contacts
--LEFT JOIN T_MAP_Contacts_Ref_OrganisationalUnit ON MAP_CTCOU_CT_UID = T_Contacts.CT_UID AND MAP_CTCOU_SoftDeleteStatus = 1
--WHERE T_MAP_Contacts_Ref_OrganisationalUnit.MAP_CTCOU_UID IS NULL -- 989
-- CROSS APPLY -- = INNER JOIN
OUTER APPLY -- = LEFT JOIN
(
SELECT TOP 1
--MAP_CTCOU_UID
MAP_CTCOU_CT_UID
,MAP_CTCOU_COU_UID
,MAP_CTCOU_DateFrom
,MAP_CTCOU_DateTo
FROM T_MAP_Contacts_Ref_OrganisationalUnit
WHERE MAP_CTCOU_SoftDeleteStatus = 1
AND MAP_CTCOU_CT_UID = T_Contacts.CT_UID
/*
AND
(
(#in_DateFrom <= T_MAP_Contacts_Ref_OrganisationalUnit.MAP_KTKOE_DateTo)
AND
(#in_DateTo >= T_MAP_Contacts_Ref_OrganisationalUnit.MAP_KTKOE_DateFrom)
)
*/
ORDER BY MAP_CTCOU_DateFrom
) AS FirstOE
In PostgreSQL, starting from version 9.3, you can do that, too - just use the LATERAL keyword to achieve the same:
SELECT * FROM T_Contacts
--LEFT JOIN T_MAP_Contacts_Ref_OrganisationalUnit ON MAP_CTCOU_CT_UID = T_Contacts.CT_UID AND MAP_CTCOU_SoftDeleteStatus = 1
--WHERE T_MAP_Contacts_Ref_OrganisationalUnit.MAP_CTCOU_UID IS NULL -- 989
LEFT JOIN LATERAL
(
SELECT
--MAP_CTCOU_UID
MAP_CTCOU_CT_UID
,MAP_CTCOU_COU_UID
,MAP_CTCOU_DateFrom
,MAP_CTCOU_DateTo
FROM T_MAP_Contacts_Ref_OrganisationalUnit
WHERE MAP_CTCOU_SoftDeleteStatus = 1
AND MAP_CTCOU_CT_UID = T_Contacts.CT_UID
/*
AND
(
(__in_DateFrom <= T_MAP_Contacts_Ref_OrganisationalUnit.MAP_KTKOE_DateTo)
AND
(__in_DateTo >= T_MAP_Contacts_Ref_OrganisationalUnit.MAP_KTKOE_DateFrom)
)
*/
ORDER BY MAP_CTCOU_DateFrom
LIMIT 1
) AS FirstOE
Try using a subquery in your ON clause. An abstract example:
SELECT
*
FROM table1
JOIN table2 ON table2.id = (
SELECT id FROM table2 WHERE table2.table1_id = table1.id LIMIT 1
)
WHERE
...

Multiple MAX values select using inner join

I have query that work for me only when values in the StakeValue don't repeat.
Basically, I need to select maximum values from SI_STAKES table with their relations from two other tables grouped by internal type.
SELECT a.StakeValue, b.[StakeName], c.[ProviderName]
FROM SI_STAKES AS a
INNER JOIN SI_STAKESTYPES AS b ON a.[StakeTypeID] = b.[ID]
INNER JOIN SI_PROVIDERS AS c ON a.[ProviderID] = c.[ID] WHERE a.[EventID]=6
AND a.[StakeGroupTypeID]=1
AND a.StakeValue IN
(SELECT MAX(d.StakeValue) FROM SI_STAKES AS d
WHERE d.[EventID]=a.[EventID] AND d.[StakeGroupTypeID]=a.[StakeGroupTypeID]
GROUP BY d.[StakeTypeID])
ORDER BY b.[StakeName], a.[StakeValue] DESC
Results for example must be:
[ID] [MaxValue] [StakeTypeID] [ProviderName]
1 1,5 6 provider1
2 3,75 7 provider2
3 7,6 8 provider3
Thank you for your help
There are two problems to solve here.
1) Finding the max values per type. This will get the Max value per StakeType and make sure that we do the exercise only for the wanted events and group type.
SELECT StakeGroupTypeID, EventID, StakeTypeID, MAX(StakeValue) AS MaxStakeValue
FROM SI_STAKES
WHERE Stake.[EventID]=6
AND Stake.[StakeGroupTypeID]=1
GROUP BY StakeGroupTypeID, EventID, StakeTypeID
2) Then we need to get only one return back for that value since it may be present more then once.
Using the Max Value, we must find a unique row for each I usually do this by getting the Max ID is has the added advantage of getting me the most recent entry.
SELECT MAX(SMaxID.ID) AS ID
FROM SI_STAKES AS SMaxID
INNER JOIN (
SELECT StakeGroupTypeID, EventID, StakeTypeID, MAX(StakeValue) AS MaxStakeValue
FROM SI_STAKES
WHERE Stake.[EventID]=6
AND Stake.[StakeGroupTypeID]=1
GROUP BY StakeGroupTypeID, EventID, StakeTypeID
) AS SMaxVal ON SMaxID.StakeTypeID = SMaxVal.StakeTypeID
AND SMaxID.StakeValue = SMaxVal.MaxStakeValue
AND SMaxID.EventID = SMaxVal.EventID
AND SMaxID.StakeGroupTypeID = SMaxVal.StakeGroupTypeID
3) Now that we have the ID's of the rows that we want, we can just get that information.
SELECT Stakes.ID, Stakes.StakeValue, SType.StakeName, SProv.ProviderName
FROM SI_STAKES AS Stakes
INNER JOIN SI_STAKESTYPES AS SType ON Stake.[StakeTypeID] = SType.[ID]
INNER JOIN SI_PROVIDERS AS SProv ON Stake.[ProviderID] = SProv.[ID]
WHERE Stake.ID IN (
SELECT MAX(SMaxID.ID) AS ID
FROM SI_STAKES AS SMaxID
INNER JOIN (
SELECT StakeGroupTypeID, EventID, StakeTypeID, MAX(StakeValue) AS MaxStakeValue
FROM SI_STAKES
WHERE Stake.[EventID]=6
AND Stake.[StakeGroupTypeID]=1
GROUP BY StakeGroupTypeID, EventID, StakeTypeID
) AS SMaxVal ON SMaxID.StakeTypeID = SMaxVal.StakeTypeID
AND SMaxID.StakeValue = SMaxVal.MaxStakeValue
AND SMaxID.EventID = SMaxVal.EventID
AND SMaxID.StakeGroupTypeID = SMaxVal.StakeGroupTypeID
)
You can use the over clause since you're using T-SQL (hopefully 2005+):
select distinct
a.stakevalue,
max(a.stakevalue) over (partition by a.staketypeid) as maxvalue,
b.staketypeid,
c.providername
from
si_stakes a
inner join si_stakestypes b on
a.staketypeid = b.id
inner join si_providers c on
a.providerid = c.id
where
a.eventid = 6
and a.stakegrouptypeid = 1
Essentially, this will find the max a.stakevalue for each a.staketypeid. Using a distinct will return one and only one row. Now, if you wanted to include the min a.id along with it, you could use row_number to accomplish this:
select
s.id,
s.maxvalue,
s.staketypeid,
s.providername
from (
select
row_number() over (order by a.stakevalue desc
partition by a.staketypeid) as rownum,
a.id,
a.stakevalue as maxvalue,
b.staketypeid,
c.providername
from
si_stakes a
inner join si_stakestypes b on
a.staketypeid = b.id
inner join si_providers c on
a.providerid = c.id
where
a.eventid = 6
and a.stakegrouptypeid = 1
) s
where
s.rownum = 1