I was writing a PostgreSQL function. In that function, I had 2 cases to be checked.
Check if a value exists in the array given
Check if a value does not exist in an array
below are the queries I'm trying
For the first case
SELECT * FROM TableA A
INNER JOIN TableB B on A.inuri = B.resource_uri
INNER JOIN TableI I on I.resource_id = B.resource_id
WHERE B.resource_type like '%%' AND
outuri='./a/b(d91dae45-9e10-43c5-bf08-f52ec80732d3)' AND (("isDeleted"='true')) OR A.inuri = ANY
(
'{./a/b(d91dae45-9e10-43c5-bf08-f52ec80732d3)/c(ee0cc326-fbaf-4d04-a9a6-31d515dea1f6),
./a/b(d91dae45-9e10-43c5-bf08-f52ec80732d3)/c(ee0cc326-fbaf-4d04-a9a6-31d515dea1f6)/d(f0576f89-1e0e-4eda-b498-0976f3e19c5c),
./a/b(d91dae45-9e10-43c5-bf08-f52ec80732d3)/c(ee0cc326-fbaf-4d04-a9a6-31d515dea1f6)/d(baf1d782-77f8-4372-9601-47a486f0700a)}'
)
and for the second case
SELECT * FROM TableA A
INNER JOIN TableB B on A.inuri = B.resource_uri
INNER JOIN TableI I on I.resource_id = B.resource_id
WHERE B.resource_type like '%%' AND
outuri='./a/b(d91dae45-9e10-43c5-bf08-f52ec80732d3)' AND (("isDeleted"='false')) AND A.inuri NOT IN
(
'{./a/b(d91dae45-9e10-43c5-bf08-f52ec80732d3)/c(ee0cc326-fbaf-4d04-a9a6-31d515dea1f6),
./a/b(d91dae45-9e10-43c5-bf08-f52ec80732d3)/c(ee0cc326-fbaf-4d04-a9a6-31d515dea1f6)/d(f0576f89-1e0e-4eda-b498-0976f3e19c5c),
./a/b(d91dae45-9e10-43c5-bf08-f52ec80732d3)/c(ee0cc326-fbaf-4d04-a9a6-31d515dea1f6)/d(baf1d782-77f8-4372-9601-47a486f0700a)}'
)
The first case works without any issue. But for the second case, it won't work when multiple values are passed.
Eg: if I give
A.inuri NOT IN
(
'{./a/b(d91dae45-9e10-43c5-bf08-f52ec80732d3)/c(ee0cc326-fbaf-4d04-a9a6-31d515dea1f6)/d(f0576f89-1e0e-4eda-b498-0976f3e19c5c)}'
)
I will get all except ./a/b(d91dae45-9e10-43c5-bf08-f52ec80732d3)/c(ee0cc326-fbaf-4d04-a9a6-31d515dea1f6)/d(f0576f89-1e0e-4eda-b498-0976f3e19c5c). But if I give 3 of them it is not validating anything. I will get all 3 items listed in the NOT IN Clause
How can I fix this?
You need to use
A.inuri <> ALL (.... your array here ...)
Related
There is an example request in which there are several joins.
SELECT DISTINCT ON(a.id_1) 1, a.name, b.task, c.created_at
FROM a
INNER JOIN b ON a.id_2 = b.id
INNER JOIN c ON a.ID_2 = c.id
WHERE a.deleted_at IS NULL
ORDER BY a.id_1 desc
In this case, the query will work, sorting by unique values of id_1 will take place. But I need to sort by the column a.name. In this case, postresql will swear with the words ERROR: SELECT DISTINCT ON expressions must match initial ORDER BY expressions.
The following query can serve as a solution to the problem:
SELECT *
FROM(
SELECT DISTINCT ON(a.id_1) a.name, b.task, c.created_at
FROM a
INNER JOIN b ON a.id_2 = b.id
INNER JOIN c ON a.ID_2 = c.id
WHERE a.deleted_at IS NULL
)
ORDER_BY a.name desc
But in reality the database is very large and such a query is not optimal. Are there other ways to sort by the selected column while keeping one uniqueness?
Given that I have a list of repeating ids that I need to fetch some additional data to populate xls spreadsheet, how can I do that. "IN" clause returns only 1 match, but I need a row for each occurrence of an Id. I looked at PIVOT, thinking I could create a select list and then do inner join.
Select m.Id, m.LegalName, m.OtherId
from MyTable m
where m.OtherId in (1,2,1,1,3,1,4,4,2,1)
You can use VALUES clause :
SELECT t.id as OtherId, m.id, m.LegalName
FROM ( VALUES (1),(2),(1),(1),(3),(1),(4),(4),(2),(1)
) t(ID) INNER JOIN
MyTable m
ON m.OtherId = t.id;
I have this SQL:
select * from `posts`
where `posts`.`deleted_at` is null
and `expire_at` >= '2017-03-26 21:23:42.000000'
and (
select count(distinct tags.id) from `tags`
inner join `post_tag` on `tags`.`id` = `post_tag`.`tag_id`
where `post_tag`.`post_id` = `posts`.`id`
and (`tags`.`tag` like 'PHP' or `tags`.`tag` like 'pop' or `tags`.`tag` like 'UI')
) >= 1
Is it possible order the results by number of tags in posts?
Maybe add there alias?
Any information can help me.
Convert your correlated subquery into a join:
select p.*
from posts p
join (
select pt.post_id,
count(distinct t.id) as tag_count
from tags t
inner join post_tag pt on t.id = pt.tag_id
where t.tag in ('PHP', 'pop', 'UI')
group by pt.post_id
) pt on p.id = pt.post_id
where p.deleted_at is null
and p.expire_at >= '2017-03-26 21:23:42.000000'
order by pt.tag_count desc;
Also, note that I changed the bunch of like and or to single IN because you are not matching any pattern i.e. there is no % in the string. So, better using single IN instead.
Also, if you have defined your table names, column names etc keeping keywords etc in mind, you shouldn't have the need to use the backticks. They make reading a query difficult.
My basic question has to do with updating multiple columns at once from specified values in my query. The reason I want to do this is that I am updating my values from a ginormous table so I only want to query it once in order to reduce run time. Here is an example of an example select statement that returns the value I want for just one of the columns I need to update:
select a.Value
from Table1
left outer join
(
select ID, FilterCol1, FilterCol2, Value
from Table2
) a on a.ID = Table1.ID
where {Condition1a on FilterCol1}
and {Condition2a on FilterCol2}
In order to update multiple columns at once I would like to be able do something like this (but it returns NULL):
Update T1
set T1Value1 = (select a.Value where {Condition1a on FilterCol1}
and {Condition2a on FilterCol2)
,T1Value2 = (select a.Value where {Condition1b on FilterCol1}
and {Condition2b on FilterCol2})
from Table1 T1
left outer join
(
select ID, FilterCol1, FilterCol2, Value
from Table2
) a on a.ID = Table1.ID
Any help figuring this out would be greatly appreciated, let me know if you have any questions or if I made any errors. Thanks!
EDIT: I think I have identified the problem, but I'm not sure of a solution yet. I think seeing the issue requires a little more context: The select from table 2 is actually an unpivot on a wide table. This means that when the left outer join is applied, there will be multiple rows for a given ID. What the case statement that Earl suggested seems to be doing (and I assume this is happening with the where clause as well) is comparing my Conditions to only the first row of the columns from a. Since my conditions are meant to help determine which of the rows from a is chosen, they will always evaluate false for the first row (I know this just from what I know about the data), hence my perpetual NULL values. Does anyone know of a workaround to look at the other rows in a?
UPDATE T1
SET T1Value1 = CASE WHEN (FilterCol1 = Condition1a AND FilterCol2 = Condition2a) THEN a.Value END,
T1Value2 = CASE WHEN (FilterCol1 = Condition1b AND FilterCol2 = Condition2b) THEN a.Value END
FROM Table1 T1
left outer join
(
select ID, FilterCol1, FilterCol2, Value
) a on a.ID = Table1.ID
How can I change following query, so that I'm able to parameterize the SparePartNames?
It returns all ID's of repairs where not all mandatory spareparts were changed, in other words where at least one part is missing.
Note that the number of spareparts might change in future not only the names. Is it possible without using a stored procedure with dynamic SQL? If not, how could this SP look like?
Edit: Note that i do not need to know how to pass a list/array as parameter, this is asked myriads of time on SO. I've also already a Split table-valued-function. I'm just wondering how i could rewrite the query to be able to join(or whatever) with a list of mandatory parts, so that i'll find all records where at least one part is missing. So is it possible to use a varchar-parameter like '1264-3212,1254-2975' instead of a list of NOT EXISTS? Sorry for the confusion if it was not clear in the first place.
SELECT d.idData
FROM tabData d
INNER JOIN modModel AS m ON d.fiModel = m.idModel
WHERE (m.ModelName = 'MT27I')
AND (d.fiMaxServiceLevel >= 2)
AND (d.Manufacture_Date < '20120511')
AND (NOT EXISTS
(SELECT NULL
FROM tabDataDetail AS td
INNER JOIN tabSparePart AS sp ON sp.idSparePart = td.fiSparePart
WHERE (td.fiData = d.idData)
AND (sp.SparePartName = '1264-3212'))
OR (NOT EXISTS
(SELECT NULL
FROM tabDataDetail AS td
INNER JOIN tabSparePart AS sp ON sp.idSparePart = td.fiSparePart
WHERE (td.fiData = d.idData)
AND (sp.SparePartName = '1254-2975'))
)
)
Unfortunately I don't see how I could use sp.SparePartName IN/NOT IN(#sparePartNames) here.
One way to do it is to create a function to split delimited strings:
CREATE FUNCTION [dbo].[Split]
(
#Delimiter char(1),
#StringToSplit varchar(512)
)
RETURNS table
AS
RETURN
(
WITH Pieces(pieceNumber, startIndex, delimiterIndex)
AS
(
SELECT 1, 1, CHARINDEX(#Delimiter, #StringToSplit)
UNION ALL
SELECT pieceNumber + 1, delimiterIndex + 1, CHARINDEX(#Delimiter, #StringToSplit, delimiterIndex + 1)
FROM Pieces
WHERE delimiterIndex > 0
)
SELECT
SUBSTRING(#StringToSplit, startIndex, CASE WHEN delimiterIndex > 0 THEN delimiterIndex - startIndex ELSE 512 END) AS Value
FROM Pieces
)
populate a table variable with the spare part names:
DECLARE #SpareParts TABLE
(
SparePartName varchar(50) PRIMARY KEY CLUSTERED
);
INSERT INTO #SpareParts
SELECT Value FROM dbo.Split(',', '1264-3212,1254-2975');
and then join to the table variable:
SELECT d.idData
FROM tabData d
INNER JOIN modModel AS m ON d.fiModel = m.idModel
WHERE (m.ModelName = 'MT27I')
AND (d.fiMaxServiceLevel >= 2)
AND (d.Manufacture_Date < '20120511')
AND EXISTS (
SELECT 1
FROM tabDataDetail AS td
INNER JOIN tabSparePart AS sp ON sp.idSparePart = td.fiSparePart
LEFT JOIN #SpareParts AS s ON s.SparePartName = sp.SparePartName
WHERE td.fiData = d.idData
AND s.SparePartName IS NULL
)
Assuming there is (or will be) a table or view of mandatory spare parts, a list of exists can be replaced with a left join to tabDataDetail / tabSparePart pair on SparePartName; non-matches are reported back using td.fiSparePart is null.
; with mandatorySpareParts (SparePartName) as (
select '1264-3212'
union all
select '1254-2975'
)
SELECT d.idData
FROM tabData d
INNER JOIN modModel AS m ON d.fiModel = m.idModel
WHERE (m.ModelName = 'MT27I')
AND (d.fiMaxServiceLevel >= 2)
AND (d.Manufacture_Date < '20120511')
AND exists
(
SELECT null
from mandatorySpareParts msp
left join ( tabDataDetail AS td
INNER JOIN tabSparePart AS sp
ON sp.idSparePart = td.fiSparePart
AND td.fiData = d.idData
)
ON msp.SparePartName = sp.SparePartName
WHERE td.fiSparePart is null
)
Part names should be replaced by their id's, which would simplify left join and speed the query up.
EDIT: i've errorneously left filtering of td in where clause, which invalidated left join. It is now in ON clause where it belongs.
Use a table-variable and join on that.