Postgres - how to build array in select with all rows ids - sql

I would like to make something like this. Build array that I will have ids of all selected rows.
SELECT p.*,
array_agg(p.id) as places_ids,
(CASE
WHEN EXISTS(
SELECT id
FROM user_favorites uf
WHERE uf.place_id = p.id
AND uf.user_id = :userId
AND uf.deleted_at IS NULL
)
THEN true
ELSE false
END ) AS favorite
FROM (SELECT
DISTINCT ON (urv.object_id)
urv.id as recent_id,
p.id,
p.name,
p.address,
p.pictures
FROM user_recent_visits urv
JOIN places p on urv.object_id = p.id
WHERE urv.user_id = :userId
AND urv.object_type = :type
AND p.deleted_at IS NULL
AND p.status = 2
AND p.active = true
) AS p
GROUP BY p.recent_id, p.id, p.name, p.address
ORDER BY p.recent_id LIMIT 5
EDIT:
Full Error:
SQLSTATE[42883]: Undefined function: 7 ERROR: unknown compare operator for typ json LINE 30: ... GROUP BY
p.recent_id, p.id, p.name, p.address,... ^ (SQL: SELECT p.*,
array_agg(json_build_array(p.id)) as places_ids, (CASE WHEN EXISTS(
SELECT id FROM user_favorites uf WHERE uf.place_id = p.id AND
uf.user_id = :userId AND uf.deleted_at IS NULL ) THEN true ELSE false
END ) AS favorite FROM (SELECT DISTINCT ON (urv.object_id) urv.id as
recent_id, p.id, p.name, p.address, p.pictures FROM user_recent_visits
urv JOIN places p on urv.object_id = p.id WHERE urv.user_id = :userId
AND urv.object_type = :type AND p.deleted_at IS NULL AND p.status = 2
AND p.active = true ) AS p GROUP BY p.recent_id, p.id, p.name,
p.address, p.pictures ORDER BY p.recent_id LIMIT 5 )
But in this case I have error "unknown compare operator". So how to write this query to get that all ids as array.
Other question. Is it possible to do it without GROUP BY?
Thank you

Related

SQL query optimization - make only one join on table

I have a large SQL query, where I need to select some data.
SELECT p.Id, p.UserId, u.Name AS CreatedBy, p.JournalId, p.Title, pt.Name AS PublicationType, p.CreatedDate, p.MagazineTitle, /*ps.StatusId,*/ p.Authors, pb.Name AS Publisher, p.Draft,jns.Name AS JournalTitle,
ISNULL(
ISNULL(
(SELECT StatusId FROM [PublicationsStatus] WHERE StatusDate=
(SELECT MAX(StatusDate) FROM [PublicationsStatus] AS ps WHERE ps.PublicationId = p.Id )),--AND ps.UserId = #UserId ORDER BY StatusDate DESC),
(SELECT TOP(1) ActionId + 6 FROM [PublicationsQuoteSaleLines] AS pqsl WHERE pqsl.PublicationId = p.Id ORDER BY pqsl.Id)
),
1
)AS StatusId
,ISNULL(
(SELECT MAX(StatusDate) FROM [PublicationsStatus] AS ps WHERE ps.PublicationId = p.Id ),--AND ps.UserId = #UserId),
p.CreatedDate
) AS StatusDate
,ISNULL(
(cast((SELECT MAX(StatusDate) FROM [PublicationsStatus] AS ps WHERE ps.PublicationId = p.Id) as date) ),--AND ps.UserId = #UserId),
p.CreatedDate
) AS StDate
,CASE
WHEN ISNULL(
ISNULL(
(SELECT StatusId FROM [PublicationsStatus] WHERE StatusDate=
(SELECT MAX(StatusDate) FROM [PublicationsStatus] AS ps WHERE ps.PublicationId = p.Id )),--AND ps.UserId = #UserId ORDER BY StatusDate DESC),
(SELECT TOP(1) ActionId + 6 FROM [PublicationsQuoteSaleLines] AS pqsl WHERE pqsl.PublicationId = p.Id ORDER BY pqsl.Id)
),
1 ) IN (1, 7, 8) THEN 0
ELSE 1 END AS OrderCriteria
,(SELECT COUNT(*) FROM SentEmails AS se WHERE se.PublicationId = p.Id AND se.EmailType = 1 AND se.UserId = #UserId) AS NumberOfAlerts
,(SELECT COUNT(*) FROM SentEmails AS se WHERE se.PublicationId = p.Id AND se.EmailType = 3 AND se.UserId = #UserId) AS NumberOfReminders
FROM Publications AS p
LEFT JOIN PublicationTypes AS pt ON p.PublicationTypeId = pt.Id
LEFT JOIN Publishers AS pb ON p.PublisherId = pb.Id
LEFT JOIN Journals As jns ON p.JournalId = jns.Id
LEFT JOIN Users AS u ON u.Id = p.UserId
The problem is that the query is slow. AS you can see I have the same thing at OrderCriteria and the StatusId. The StatusDate I'm getting from the same table.
I thought that I could resolve the performance to make only one \
LEFT JOIN
something like this:
LEFT JOIN (
SELECT
PublicationId,
StatusId AS StatusId,
StatusDate AS StatusDate
FROM [PublicationsStatus] WHERE StatusDate=
(
SELECT MAX(StatusDate) FROM PublicationsStatus
)
) AS ps ON ps.PublicationId = p.Id
but I did not get the same results this way.
Can you please advise?
I tried to simplify your query using a few CTE to avoid doing the same subquery multiple times. You can try this out and see if it's still slow.
;WITH MaxStatusDateByPublication AS
(
SELECT
PublicationId = ps.PublicationId,
MaxStatusDate = MAX(ps.StatusDate)
FROM
[PublicationsStatus] AS ps
GROUP BY
PS.PublicationId
),
StatusForMaxDateByPublication AS
(
SELECT
StatusId = PS.StatusId,
M.PublicationId,
M.MaxStatusDate
FROM
MaxStatusDateByPublication AS M
INNER JOIN [PublicationsStatus] AS PS ON
M.PublicationId = PS.PublicationId AND
M.MaxStatusDate = PS.StatusDate
),
SentEmailsByPublicationAndType AS
(
SELECT
S.PublicationID,
S.EmailType,
AmountSentEmails = COUNT(1)
FROM
SentEmails AS S
WHERE
S.EmailType IN (1, 3) AND
S.UserID = #UserId
GROUP BY
S.PublicationID,
S.EmailType
)
SELECT
p.Id,
p.UserId,
u.Name AS CreatedBy,
p.JournalId,
p.Title,
pt.Name AS PublicationType,
p.CreatedDate,
p.MagazineTitle,
p.Authors,
pb.Name AS Publisher,
p.Draft,
jns.Name AS JournalTitle,
COALESCE(MS.StatusId, SL.StatusId, 1) AS StatusId,
ISNULL(MS.MaxStatusDate, P.CreatedDate) AS StatusDate,
ISNULL(CONVERT(DATE, MS.MaxStatusDate), P.CreatedDate) AS StDate,
CASE
WHEN COALESCE(MS.StatusId, SL.StatusId, 1) IN (1, 7, 8) THEN 0
ELSE 1
END AS OrderCriteria,
ISNULL(TY1.AmountSentEmails, 0) AS NumberOfAlerts,
ISNULL(TY3.AmountSentEmails, 0) AS NumberOfReminders
FROM
Publications AS p
LEFT JOIN PublicationTypes AS pt ON p.PublicationTypeId = pt.Id
LEFT JOIN Publishers AS pb ON p.PublisherId = pb.Id
LEFT JOIN Journals As jns ON p.JournalId = jns.Id
LEFT JOIN Users AS u ON u.Id = p.UserId
LEFT JOIN StatusForMaxDateByPublication AS MS ON P.Id = MS.PublicationId
LEFT JOIN SentEmailsByPublicationAndType AS TY1 ON
P.Id = TE.PublicationID AND
TY1.EmailType = 1
LEFT JOIN SentEmailsByPublicationAndType AS TY3 ON
P.Id = TE.PublicationID AND
TY1.EmailType = 3
OUTER APPLY (
SELECT TOP 1
StatusId = ActionId + 6
FROM
[PublicationsQuoteSaleLines] AS pqsl
WHERE
pqsl.PublicationId = P.Id
ORDER BY
pqsl.Id ASC) AS SL
Try to avoid writing the same expression several times (and specially if it involes subqueries inside a column!). Using a few CTEs and proper identing will help readability.
This is a complex query and involves several tables. If your query runs slow it might be for many different reasons. Try executing each subquery on it's own to check if they are slow or not, then try joining them 1 by 1. Indexes by the join columns will probably increase your performance if they don't exist already. Posting the full query execution plan might help.

Error in on clause comparison - Big Query

The following big query code gives the following error.
select
selected_date date,
pp.name property,
bb.bookings bb,
av.available vailable,
from
(SELECT DATE(DATE_ADD(TIMESTAMP("2017-10-01"), pos - 1, "DAY")) AS selected_date
FROM (
SELECT ROW_NUMBER() OVER() AS pos, *
FROM (FLATTEN((
SELECT SPLIT(RPAD('', 1 + DATEDIFF(TIMESTAMP(CURRENT_DATE()), TIMESTAMP("2017-10-01")), '.'),'') AS h
FROM (SELECT NULL)),h
)))) v
cross join
(select p.name name from [roomsproperties.properties] p where p.name not like '%test%' group by name) as pp
left join
(select sum(b.rooms) bookings,
p.name property,
b.checkin checkin,
b.checkout checkout
from [bookings.bookings] b
left join [roomsproperties.rooms] r on r.id = b.room_id
left join [roomsproperties.properties] p on p.id = r.property_id
where p.name not like '%test%'
and b.status not in('Rejected', 'Cancelled - By customer', 'OTP Not Varified')
group by property,checkin,checkout
) as bb on pp.name = bb.property and (v.selected_date between bb.checkin and bb.checkout)
left join
(select sum(r.quantity) available,
p.name property,
date(r.created_at) date
from [roomsproperties.rooms] r
left join [roomsproperties.properties] p on p.id = r.property_id
group by property, date
) av on pp.name = av.property and v.selected_date >= av.date
The error is,
Error: ON clause must be AND of = comparisons of one field name from each table, with all field names prefixed with table name. Consider using Standard SQL
Can any one help
You should try:
(select ...) as bb on pp.name = bb.property
WHERE v.selected_date between bb.checkin and bb.checkou
and:
(select ...) as av on pp.name = av.property
WHERE v.selected_date >= av.date

Struggling with left join

I'm struggling with left joining the earliest row in this left join.
The results are showing a 2011 date, but i know for a fact this particular row should be returning 2008.
SELECT TOP 1000
f.name as [Franchisee]
,p.paid_date as paid_date
FROM franchisees_franchisee f
OUTER APPLY (SELECT TOP 1 *
FROM era_project_invoice_payment p
WHERE f.franchiseeid = p.franchiseeid
and p.deleted = 0 and p.payment_confirmed = 1
ORDER BY p.eraprojectinvoicepaymentid ASC) p
where
f.deleted = 0
and f.name LIKE '%VKlinkosch%'
Below returns the correct, 2008 date.
SELECT TOP 1000
f.name as [Franchisee]
,min(p.paid_date) as paid_date
from [era_uat_shared].[dbo].[franchisees_franchisee] f
left join era_project_invoice_payment p
on f.franchiseeid = p.franchiseeid
where f.deleted = 0
and f.name LIKE '%VKlinkosch%'
GROUP BY f.name
Problem is, I need more than just the Paid Date from the payments table! :(
SELECT
f.name as [Franchisee]
, p.*
FROM franchisees_franchisee f
INNER JOIN
(
SELECT
ROW_NUMBER() OVER (PARTITION BY franchiseeid ORDER BY paid_date ASC) rn
, p.*
FROM
era_project_invoice_payment p
WHERE
deleted = 0
AND payment_confirmed = 1
) p
ON
f.franchiseeid = p.franchiseeid
AND f.deleted = 0
AND f.name LIKE '%VKlinkosch%'
AND p.rn = 1

Cannot perform an aggregate function on an expression containing an aggregate or a subquery sql server 2012

I am performing a query and its showing an error Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
the query is
SELECT
tbl_Product.ID,
tbl_Product.ArticleID,
tbl_Product.Title,
tbl_Product.Description,
tbl_Product.Price,
tbl_ProductType.Name,
tbl_Status.StatusName,
tbl_VisibilityStatus.VisibilityStatus,
MAX(
CASE
WHEN tbl_RelatedProduct.TypeOfRelation = 1 THEN 'Bundle'
WHEN tbl_Product.ID IN
(
select tbl_RelatedProduct.Product2ID
from tbl_RelatedProduct
where tbl_RelatedProduct.Product1ID=9 and tbl_RelatedProduct.TypeOfRelation=1) THEN 'Bundle'
END
) 'Bundle',
MAX(
CASE
WHEN tbl_RelatedProduct.TypeOfRelation = 2 THEN 'Follower' END) 'Follower',
MAX(
CASE
WHEN tbl_RelatedProduct.TypeOfRelation = 3 THEN 'Related' END) 'Related'
FROM
tbl_Product inner JOIN
tbl_ProductType ON tbl_Product.ProductTypeId = tbl_ProductType.ID Inner JOIN
tbl_Status ON tbl_Product.StatusID = tbl_Status.ID Inner JOIN
tbl_VisibilityStatus ON tbl_Product.VisibilityID = tbl_VisibilityStatus.ID
left JOIN tbl_RelatedProduct ON tbl_Product.ID = tbl_RelatedProduct.Product1ID
group by
tbl_Product.ID,
tbl_Product.ArticleID,
tbl_Product.Title,
tbl_Product.Description,
tbl_Product.Price,
tbl_ProductType.Name,
tbl_Status.StatusName,
tbl_VisibilityStatus.VisibilityStatus
order by tbl_Product.Title
ANyone know how to help on this...plsss
The below line is causing an issue:
WHEN tbl_Product.ID IN
(
select tbl_RelatedProduct.Product2ID
from tbl_RelatedProduct
where tbl_RelatedProduct.Product1ID=9 and tbl_RelatedProduct.TypeOfRelation=1) THEN 'Bundle'
END
) 'Bundle',
You are using MAX with CASE and one of the statements within CASE uses a subquery, which is causing the error. You might want to consider using joins instead of subqueries to implement this.
SELECT tbl_Product.ID,tbl_Product.ArticleID,tbl_Product.Title,tbl_Product.Description,tbl_Product.Price,tbl_ProductType.Name,tbl_Status.StatusName, tbl_VisibilityStatus.VisibilityStatus,
Case when ((select count(1) from tbl_RelatedProduct where tbl_RelatedProduct.TypeOfRelation = 1 and tbl_RelatedProduct.Product1ID = tbl_Product.Id) > 0) then 1
when ((select count(1) from tbl_RelatedProduct where tbl_RelatedProduct.TypeOfRelation = 1 and tbl_RelatedProduct.Product2ID = tbl_Product.Id) > 0) then 1
else 0 end as Bundle,
(select count(1) from tbl_RelatedProduct where tbl_RelatedProduct.TypeOfRelation = 2 and tbl_RelatedProduct.Product1ID = tbl_Product.Id) as Follower,
(select count(1) from tbl_RelatedProduct where tbl_RelatedProduct.TypeOfRelation = 3 and tbl_RelatedProduct.Product1ID = tbl_Product.Id) as Related
FROM tbl_Product
inner JOIN
tbl_ProductType ON tbl_Product.ProductTypeId = tbl_ProductType.ID Inner JOIN
tbl_Status ON tbl_Product.StatusID = tbl_Status.ID
Inner JOIN
tbl_VisibilityStatus ON tbl_Product.VisibilityID = tbl_VisibilityStatus.ID
Its resolved with this query :)
I think I see what you are trying to do, and it is a bit strange. I would output this all as a single column, and lose the MAX aggregate as follows:
SELECT
p.ID,
p.ArticleID,
p.Title,
p.Description,
p.Price,
pt.Name,
s.StatusName,
v.VisibilityStatus,
CASE
WHEN rp.TypeOfRelation = 1 OR (rp2.Product1ID = 9 AND rp2.TypeOfRelation = 1)
THEN 'Bundle'
WHEN rp.TypeOfRelation = 2
THEN 'Follower'
WHEN rp.TypeOfRelation = 3
THEN 'Related'
ELSE Null
END AS Relation
FROM
tbl_Product p
INNER JOIN tbl_ProductType pt
ON p.ProductTypeId = pt.ID
INNER JOIN tbl_Status s
ON p.StatusID = s.ID
INNER JOIN tbl_VisibilityStatus v
ON p.VisibilityID = v.ID
LEFT JOIN tbl_RelatedProduct rp
ON p.ID = rp.Product1ID
LEFT JOIN tbl_RelatedProduct rp2
ON p.ID = rp2.Product2ID
ORDER BY p.Title
If you would still like to have them in separate columns, just break up the CASE statement as follows:
SELECT
p.ID,
p.ArticleID,
p.Title,
p.Description,
p.Price,
pt.Name,
s.StatusName,
v.VisibilityStatus,
CASE
WHEN rp.TypeOfRelation = 1 OR (rp2.Product1ID = 9 AND rp2.TypeOfRelation = 1)
THEN 'Bundle'
ELSE Null
END AS Bundle,
CASE
WHEN rp.TypeOfRelation = 2
THEN 'Follower'
ELSE Null
END AS Follower,
CASE
WHEN rp.TypeOfRelation = 3
THEN 'Related'
ELSE Null
END AS Related
FROM
tbl_Product p
INNER JOIN tbl_ProductType pt
ON p.ProductTypeId = pt.ID
INNER JOIN tbl_Status s
ON p.StatusID = s.ID
INNER JOIN tbl_VisibilityStatus v
ON p.VisibilityID = v.ID
LEFT JOIN tbl_RelatedProduct rp
ON p.ID = rp.Product1ID
LEFT JOIN tbl_RelatedProduct rp2
ON p.ID = rp2.Product2ID
ORDER BY p.Title

SQL join two simple query with count and groupby

hello i have 2 queries and i wanna join together but i don't know how...
SELECT *, count(*) as invii
FROM professionisti JOIN preventivi_invii ON
professionisti.email=preventivi_invii.email
GROUP BY professionisti.email
HAVING invii> 300
SELECT *, count(*) as acquisti
FROM professionisti JOIN contatti_acquistati ON
professionisti.email=contatti_acquistati.email
GROUP BY professionisti.email
HAVING acquisti> 5
the problem for me is multiple count and the group by with same column.
thank u
How about the below query. You would just change the WHERE clause to meet your needs.
SQL Fiddle Example:
SELECT * FROM
(
SELECT p.email,
CASE WHEN ISNULL(m1.invii) THEN 0 ELSE m1.invii END AS invii,
CASE WHEN ISNULL(m2.acquisti) THEN 0 ELSE m2.acquisti END AS acquisti
FROM professionisti p
LEFT JOIN
(
SELECT pp.email, COUNT(*) AS invii
FROM preventivi_invii pp
GROUP BY pp.email
) AS m1 ON p.email = m1.email
LEFT JOIN
(
SELECT c.email, COUNT(*) AS acquisti
FROM contatti_acquistati c
GROUP BY c.email
) AS m2 ON p.email = m2.email
) AS mm
WHERE mm.invii = 0
OR mm.acquisti = 0;
Or you could use:
SELECT * FROM
(
SELECT p.email,
(
SELECT
CASE WHEN ISNULL(COUNT(*)) THEN 0 ELSE COUNT(*) END
FROM preventivi_invii pp
WHERE pp.email = p.email
) AS invii,
(
SELECT
CASE WHEN ISNULL(COUNT(*)) THEN 0 ELSE COUNT(*) END
FROM contatti_acquistati c
WHERE c.email = p.email
) AS acquisti
FROM professionisti p
) AS mm
WHERE mm.invii = 0
OR mm.acquisti = 0