Fetching values from second table in the Query - sql

select *
from EFLOVRelationship R
where R.parentEFLOVValueId = '5320'
and R.childEFLOVId in (select Eflovid
from EFFieldLOVStaticValue
where efLovId = 49)
In the above query I want to fetch 2 columns from EFFieldLOVStaticValue table and display.
Thanks in advance

Use Inner Join
SELECT R.*,
V.field1,
V.field2
FROM eflovrelationship R
INNER JOIN effieldlovstaticvalue V
ON R.childeflovid = V.eflovid
WHERE R.parenteflovvalueid = '5320'
AND V.eflovid = 49
If your table has 1:N relationship then use Distinct to avoid duplicates in result
If you want just one record from effieldlovstaticvalue table for each R.childeflovid column then use Cross Apply but you need to use required column to order the result and choose the top 1 record
SELECT R.*,
CS.field1,
CS.field2
FROM eflovrelationship R
CROSS apply (SELECT TOP 1 field1,
field2
FROM effieldlovstaticvalue V
WHERE R.childeflovid = V.eflovid
AND eflovid = 49
ORDER BY someordercolumn) CS
WHERE R.parenteflovvalueid = '5320'

Use join:
select R.*, sv.?, sv.?
from EFLOVRelationship R join
EFFieldLOVStaticValue sv
ON sv.Eflovid = R.childEFLOVId and sv.efLovId = 49
where R.parentEFLOVValueId = '5320'

Related

SELECT NOT IN with multiple columns in subquery

Regarding the statement below, sltrxid can exist as both ardoccrid and ardocdbid. I'm wanting to know how to include both in the NOT IN subquery.
SELECT *
FROM glsltransaction A
INNER JOIN cocustomer B ON A.acctid = B.customerid
WHERE sltrxstate = 4
AND araccttype = 1
AND sltrxid NOT IN(
SELECT ardoccrid,ardocdbid
FROM arapplyitem)
I would recommend not exists:
SELECT *
FROM glsltransaction t
INNER JOIN cocustomer c ON c.customerid = t.acctid
WHERE
??.sltrxstate = 4
AND ??.araccttype = 1
AND NOT EXISTS (
SELECT 1
FROM arapplyitem a
WHERE ??.sltrxid IN (a.ardoccrid, a.ardocdbid)
)
Note that I changed the table aliases to things that are more meaningful. I would strongly recommend prefixing the column names with the table they belong to, so the query is unambiguous - in absence of any indication, I represented this as ?? in the query.
IN sometimes optimize poorly. There are situations where two subqueries are more efficient:
SELECT *
FROM glsltransaction t
INNER JOIN cocustomer c ON c.customerid = t.acctid
WHERE
??.sltrxstate = 4
AND ??.araccttype = 1
AND NOT EXISTS (
SELECT 1
FROM arapplyitem a
WHERE ??.sltrxid = a.ardoccrid
)
AND NOT EXISTS (
SELECT 1
FROM arapplyitem a
WHERE ??.sltrxid = a.ardocdbid
)

SQL Query find results with multiple values

I have a list of contracts like this query:
select
r.vnum, r.BEITRAGSGR
from
ufrisk r
inner join
ufvert v on r.vnum = v.vnum
inner join
allgvert a on a.vnum = r.vnum
where
a.version = r.version
How can I search for all contracts that have more than one (different) value in the column r.BEITRAGSGR?
Assuming vnum is a "contract", you can use aggregation:
select vnum
from ufrisk
group by vnum
having min(BEITRAGSGR) <> max(BEITRAGSGR);
If you want the original rows, use exists:
select u.*
from ufrisk u
where exists (select 1
from ufrisk u2
where u2.vnum = u.vnum and u2.BEITRAGSGR <> u.BEITRAGSGR
);

SQL Server 2005 - cross apply, tvf, and update/delete

How can I make something like this
select
a.atest, a.btest, a.ctest, b.atest, b.btest
from
test.dbo.rm a(nolock)
cross apply
wat.dbo.ar(a.atest,a.btest) b
where
a.rmd = 9 and a.btest > 0
alter function ar(#atest varchar(25), #btest numeric(19,5))
returns table as
return
(
select atest, btest from test.dbo.rm (nolock)
where rmd = 1 and atest=#atest and btest=#btest
)
with delete statement or update. I don't want to make duplicates so after I choose one b.atest I want to delete the record with b.atest or set b.btest to 0. This query is working on table that contain about 5-10 million of records.. so it must be quick.
Use query without function:
select a.atest,a.btest,a.ctest,b.atest,b.btest
from test.dbo.rm a(nolock)
cross apply (
select top 1 atest, btest
from test.dbo.rm t (nolock)
where t.rmd = 1 and t.atest=a.atest and t.btest=a.btest
)b
where a.rmd = 9 and a.btest > 0
You can also use Left join instead of cross apply:
select *
from (
select a.atest,a.btest,a.ctest,b.atest,b.btest,
row_number() over ( partition by b.atest, b.btest order by b.id) as row
from test.dbo.rm a(nolock)
LEFT JOIN test.dbo.rm b ON b.rmd = 1 and b.atest=a.atest and b.btest=a.btest
where a.rmd = 9 and a.btest > 0
)z
where z.row = 1

Delete row from sql table where values not found in another table with multiple joins

I have the following query which returns the desired data. What I want to do is delete that data, however when I change the Select DQ.* to DELETE FROM DQ, I get an error indicating that
'... not updatable because the modification affects multiple base table'
I need to delete entries from the tbaccess_groupPermission table where appropriate module records are not found in the tbaccess_companyModules table.
WITH DQ AS
(
SELECT GP.* FROM tbaccess_groupPermission GP
JOIN tbaccess_groups G ON GP.GroupID = G.ID
WHERE G.CompanyID=6
AND GP.RoleName NOT IN
(
select Distinct(R.RoleName)
FROM tbAccess_Roles R
INNER JOIN tbAccess_CompanyModules C on R.ModuleID = C.ModuleID
WHERE C.CompanyID = 6)
)
SELECT * FROM DQ
Why not change the WITH statement to use an IN clause?
Something like
WITH DQ AS
(
SELECT GP.* FROM tbaccess_groupPermission GP
WHERE GP.GroupID IN (SELECT G.ID FROM tbaccess_groups G WHERE G.CompanyID=6)
AND GP.RoleName NOT IN
(
select Distinct(R.RoleName)
FROM tbAccess_Roles R
INNER JOIN tbAccess_CompanyModules C on R.ModuleID = C.ModuleID
WHERE C.CompanyID = 6)
)

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
...