trying to merge 2 views - sql

I need to retrieve the data provided by this view :
BLICK_1_DESCR_LIST.
I didn't find how to create it directly. So I created the view BLICK_1_DESCR_NO_LIST which is used in the second view BLICK_1_DESCR_LIST.
I would like to do it in one view which is better.
CREATE VIEW BLICK_1_DESCR_NO_LIST
AS SELECT ITEM_ID , MIN(ITEM_DESCR_NO) MIN_I_D_NO,
COUNT(ITEM_DESCR_NO) COUNT_I_D_NO FROM BLICK_ITEM_DESCR
GROUP BY ITEM_ID
UNION
SELECT ID , 0 ZERO, 0 ZERO2 FROM BLICK_ITEM
LEFT JOIN BLICK_ITEM_DESCR ON BLICK_ITEM.ID = BLICK_ITEM_DESCR.ITEM_ID
WHERE ITEM_DESCR_NO IS NULL;
CREATE VIEW BLICK_1_DESCR_LIST
AS SELECT V1.ITEM_ID, V1.MIN_I_D_NO, V1.COUNT_I_D_NO, T1.ITEM_DESCR
FROM BLICK_1_DESCR_NO_LIST V1
LEFT JOIN BLICK_ITEM_DESCR T1 ON V1.ITEM_ID = T1.ITEM_ID
AND V1.MIN_I_D_NO = T1.ITEM_DESCR_NO
ORDER BY ITEM_ID;

You can just incorporate the first view as a subquery:
CREATE VIEW BLICK_1_DESCR_LIST AS
SELECT V1.ITEM_ID, V1.MIN_I_D_NO, V1.COUNT_I_D_NO, T1.ITEM_DESCR
FROM ((SELECT ITEM_ID, MIN(ITEM_DESCR_NO) as MIN_I_D_NO,
COUNT(ITEM_DESCR_NO) as COUNT_I_D_NO
FROM BLICK_ITEM_DESCR
GROUP BY ITEM_ID
) UNION
(SELECT ID, 0, 0
FROM BLICK_ITEM LEFT JOIN
BLICK_ITEM_DESCR
ON BLICK_ITEM.ID = BLICK_ITEM_DESCR.ITEM_ID
WHERE ITEM_DESCR_NO IS NULL
)) V1 LEFT JOIN
BLICK_ITEM_DESCR T1
ON V1.ITEM_ID = T1.ITEM_ID AND
V1.MIN_I_D_NO = T1.ITEM_DESCR_NO
ORDER BY ITEM_ID;

Related

Query result not working with array type in PostgreSQL

I have two tables which contains a column with data type array in PostgreSQL. The structure is like below:
tbl_tour_packages
tbl_header_images
I have a query which contains several joins. The query is working fine with other joins and showing no error. But missing the values from tbl_header_images.
The query is:
SELECT
t1.tour_id AS pid,
t1.tour_name AS title,
t1.tour_duration AS nights,
t1.tour_price_full AS price,
t1.discount AS discount,
t1.tour_seo_title AS seo,
t3.category AS category,
t4.image_names[1] AS image_url,
CASE WHEN max(s.state_name) IS NULL THEN NULL ELSE array_agg(s.state_name) END AS state,
CASE WHEN max(o.destination) IS NULL THEN NULL ELSE array_agg(o.destination) END AS destinations
FROM tbl_tour_packages t1
LEFT JOIN tbl_countries t2 ON t1.tour_country_iso = t2.iso
LEFT JOIN tbl_categories t3 on t1.tour_category_id = t3.id
LEFT JOIN tbl_header_images t4 ON t1.tour_id = t4.package_id
LEFT JOIN tbl_states AS s ON (t1.tour_state #> array[s.state_code])
LEFT JOIN tbl_destinations AS o ON (t1.tour_destination #> array[o.id])
WHERE t1.tour_status = 1
GROUP BY 1,7,8
ORDER BY view_count ASC LIMIT 6
I want to get the 'image_name' from tbl_header_images. Any quick help or suggestion will be appreciated.
before WHERE clause you should be able to do something like:
, unnest(image_names) _image_names
and then in select statement aggregate that back into an array
array_agg(_image_names) AS image_names
I don't quite get the t4.image_names[1] AS image_url attempt, but I'm sure you can pick it up from here.
so the whole query would be something like:
edit: I've stripped extra groupping
SELECT
t1.tour_id AS pid,
t1.tour_name AS title,
t1.tour_duration AS nights,
t1.tour_price_full AS price,
t1.discount AS discount,
t1.tour_seo_title AS seo,
t3.category AS category,
(array_agg(_image_names))[1] AS image_url,
CASE WHEN max(s.state_name) IS NULL THEN NULL ELSE array_agg(s.state_name) END AS state,
CASE WHEN max(o.destination) IS NULL THEN NULL ELSE array_agg(o.destination) END AS destinations
FROM tbl_tour_packages t1
LEFT JOIN tbl_countries t2 ON t1.tour_country_iso = t2.iso
LEFT JOIN tbl_categories t3 on t1.tour_category_id = t3.id
LEFT JOIN tbl_header_images t4 ON t1.tour_id = t4.package_id
LEFT JOIN tbl_states AS s ON (t1.tour_state #> array[s.state_code])
LEFT JOIN tbl_destinations AS o ON (t1.tour_destination #> array[o.id])
, unnest(t4.image_names) AS _image_names
WHERE t1.tour_status = 1
GROUP BY 1,7
ORDER BY view_count ASC LIMIT 6
alternatively I'd go with subselect:
SELECT t1.*,
(SELECT image_names[1] FROM tbl_header_images WHERE package_id = t1.tour_id) AS image_url
FROM t1, t2, t3
WHERE ...

Join same column from multiple tables

Below is my current code. I'm not sure what the best way is to amend this to give me the results I need.
SELECT
T1.SC,
T1.AN,
T1.DOFS_DATE,
T2.M_ID,
T3.OPDT,
T4.MARKER,
T5.E_DTE,
T5.E_TME,
T5.E_PST_DTE,
T5.E_AMT,
T5.E_NAR_O,
T5.E_NAR_T
FROM E_Base.AR_MyTable T1
LEFT JOIN E_Base.Translation T2
ON T1.SC = T2.SC
AND T1.AN = T2.AN
LEFT JOIN E_Base.BA T3
ON T2.M_ID = T3.M_ID
LEFT JOIN E_Base.APF T4
ON T3.M_ID = T4.M_ ID
AND MARKER = 54
LEFT JOIN U_DB.TEH_201804 T5
ON T2.M_ID = T5.M_ID
AND T1.DOFS_DATE = T5.E_PST_DTE
QUALIFY ROW_NUMBER() OVER (PARTITION BY T2.M_ID ORDER BY T2.ID_END_DATE DESC, T3.E_END_DATE DESC) = 1
The above code works. However, it is the final left join on T5 where I need help.
In T1 each M_ID has assigned it's own DOFS_DATE that could be any date within the year and I want the data from T5 U_DB.TEH_201804 for the matching date. However, 5 U_DB.TEH_201804 relates to only April 2018. There are 12 tables with the same database (201804, 201805, 201806 etc) that all have the exact same columns but relate to a different month within the year.
Ideally, I want to left join the columns from T5 once but search all 12 tables within the database to bring back the data where the dates correspond.
I was thinking UNION but am unsure how to work this in.
Any help would be greatly appreciated!
Thanks
You could change you code related to table t5 wuth a left join on a subquery that select the union all for all the bale you need ...... (i have named the subquery TT)
SELECT
T1.SC,
T1.AN,
T1.DOFS_DATE,
T2.M_ID,
T3.OPDT,
T4.MARKER,
TT.E_DTE,
TT.E_TME,
TT.E_PST_DTE,
TT.E_AMT,
TT.E_NAR_O,
TT.E_NAR_T
FROM E_Base.AR_MyTable T1
LEFT JOIN E_Base.Translation T2
ON T1.SC = T2.SC
AND T1.AN = T2.AN
LEFT JOIN E_Base.BA T3
ON T2.M_ID = T3.M_ID
LEFT JOIN E_Base.APF T4
ON T3.M_ID = T4.M_ ID
AND MARKER = 54
LEFT JOIN (
select *
FROM U_DB.TEH_201804
UNION ALL
select *
FROM U_DB.TEH_201805
UNION ALL
select *
FROM U_DB.TEH_201806
UNION ALL
select *
FROM U_DB.TEH_201807
UNION ALL
.....
) TT ON T2.M_ID = TT.M_ID
AND T1.DOFS_DATE = TT.E_PST_DTE
QUALIFY ROW_NUMBER() OVER (PARTITION BY T2.M_ID ORDER BY T2.ID_END_DATE DESC, T3.E_END_DATE DESC) = 1
It's hard to tell without additional details like explain and QueryLog step data.
Based on #scaisEdge answer:
You can try to move the first two joins into a Derived Table to apply the ROW_NUMBER early (possible because you do Outer Joins only):
SELECT
dt.*,
T4.MARKER,
TT.E_DTE,
TT.E_TME,
TT.E_PST_DTE,
TT.E_AMT,
TT.E_NAR_O,
TT.E_NAR_T
FROM
(
SELECT
T1.SC,
T1.AN,
T1.DOFS_DATE,
T2.M_ID,
T3.OPDT
FROM E_Base.AR_MyTable T1
LEFT JOIN E_Base.Translation T2
ON T1.SC = T2.SC
AND T1.AN = T2.AN
LEFT JOIN E_Base.BA T3
ON T2.M_ID = T3.M_ID
QUALIFY Row_Number()
Over (PARTITION BY T2.M_ID
ORDER BY T2.ID_END_DATE DESC, T3.E_END_DATE DESC) = 1
) AS dt
LEFT JOIN E_Base.APF T4
ON dt.M_ID = T4.M_ID
AND MARKER = 54
LEFT JOIN
(
SELECT *
FROM U_DB.TEH_201804
UNION ALL
SELECT *
FROM U_DB.TEH_201805
UNION ALL
SELECT *
FROM U_DB.TEH_201806
UNION ALL
SELECT *
FROM U_DB.TEH_201807
UNION ALL
.....
) TT
ON dt.M_ID = TT.M_ID
AND dt.DOFS_DATE = TT.E_PST_DTE
It might also help the optimizer to provide additional info about the data ranges. Those tables should have CHECK-constraints to tell the optimizer that they contain only data from a single month, if they don't exist try adding a WHERE-condition to each Select, e.g. WHERE E_PST_DTE BETWEEN DATE '2018-04-01' AND DATE '2018-04-30'.
Of course, always check Explain if the plan actually changes...

How to join three tables with distinct

I'm trying to join three tables to pull back a list of distinct blog posts with associated assets (images etc) but I keep coming up a cropper. The three tablets are tblBlog, tblAssetLink and tblAssets. The Blog tablet hold the blog, the asset table holds the assets and the Assetlink table links the two together.
tblBlog.BID is the PK in blog, tblAssets.AID is the PK in Assets.
This query works but pulls back multiple posts for the same record. I've tried to use select distinct and group by and even union but as my knowledge is pretty poor with SQL - they all error.
I'd like to also discount any assets that are marked as deleted (tblAssets.Deleted = true) but not hide the associated Blog post (if that's not marked as deleted). If anyone can help - it would be much appreciated! Thanks.
Here's my query so far....
SELECT dbo.tblBlog.BID,
dbo.tblBlog.DateAdded,
dbo.tblBlog.PMonthName,
dbo.tblBlog.PDay,
dbo.tblBlog.Header,
dbo.tblBlog.AddedBy,
dbo.tblBlog.PContent,
dbo.tblBlog.Category,
dbo.tblBlog.Deleted,
dbo.tblBlog.Intro,
dbo.tblBlog.Tags,
dbo.tblAssets.Name,
dbo.tblAssets.Description,
dbo.tblAssets.Location,
dbo.tblAssets.Deleted AS Expr1,
dbo.tblAssetLink.Priority
FROM dbo.tblBlog
LEFT OUTER JOIN dbo.tblAssetLink
ON dbo.tblBlog.BID = dbo.tblAssetLink.BID
LEFT OUTER JOIN dbo.tblAssets
ON dbo.tblAssetLink.AID = dbo.tblAssets.AID
WHERE ( dbo.tblBlog.Deleted = 'False' )
ORDER BY dbo.tblAssetLink.Priority, tblBlog.DateAdded DESC
EDIT
Changed the Where and the order by....
Expected output:
tblBlog.BID = 123
tblBlog.DateAdded = 12/04/2015
tblBlog.Header = This is a header
tblBlog.AddedBy = Persons name
tblBlog.PContent = *text*
tblBlog.Category = Category name
tblBlog.Deleted = False
tblBlog.Intro = *text*
tblBlog.Tags = Tag, Tag, Tag
tblAssets.Name = some.jpg
tblAssets.Description = Asset desc
tblAssets.Location = Location name
tblAssets.Priority = True
Use OUTER APPLY:
DECLARE #b TABLE ( BID INT )
DECLARE #a TABLE ( AID INT )
DECLARE #ba TABLE
(
BID INT ,
AID INT ,
Priority INT
)
INSERT INTO #b
VALUES ( 1 ),
( 2 )
INSERT INTO #a
VALUES ( 1 ),
( 2 ),
( 3 ),
( 4 )
INSERT INTO #ba
VALUES ( 1, 1, 1 ),
( 1, 2, 2 ),
( 2, 1, 1 ),
( 2, 2, 2 )
SELECT *
FROM #b b
OUTER APPLY ( SELECT TOP 1
a.*
FROM #ba ba
JOIN #a a ON a.AID = ba.AID
WHERE ba.BID = b.BID
ORDER BY Priority
) o
Output:
BID AID
1 1
2 1
Something like:
SELECT b.BID ,
b.DateAdded ,
b.PMonthName ,
b.PDay ,
b.Header ,
b.AddedBy ,
b.PContent ,
b.Category ,
b.Deleted ,
b.Intro ,
b.Tags ,
o.Name ,
o.Description ,
o.Location ,
o.Deleted AS Expr1 ,
o.Priority
FROM dbo.tblBlog b
OUTER APPLY ( SELECT TOP 1
a.* ,
al.Priority
FROM dbo.tblAssetLink al
JOIN dbo.tblAssets a ON al.AID = a.AID
WHERE b.BID = al.BID
ORDER BY al.Priority
) o
WHERE b.Deleted = 'False'
You cannot join three tables unless they all have the same attribute. It would work if all tables had BID, but the second join is trying to join AID. Which wont work. They all have to have BID.
Based on your comments
i would like to get is just one asset per blog post (top one ordered
by Priority)
You can change your query as following. I suggest changing the join with dbo.tblAssetLink to filtered one, which contains only one (highest priority) link for every blog.
SELECT dbo.tblBlog.BID,
dbo.tblBlog.DateAdded,
dbo.tblBlog.PMonthName,
dbo.tblBlog.PDay,
dbo.tblBlog.Header,
dbo.tblBlog.AddedBy,
dbo.tblBlog.PContent,
dbo.tblBlog.Category,
dbo.tblBlog.Deleted,
dbo.tblBlog.Intro,
dbo.tblBlog.Tags,
dbo.tblAssets.Name,
dbo.tblAssets.Description,
dbo.tblAssets.Location,
dbo.tblAssets.Deleted AS Expr1,
dbo.tblAssetLink.Priority
FROM dbo.tblBlog
LEFT OUTER JOIN
(SELECT BID, AID,
ROW_NUMBER() OVER (PARTITION BY BID ORDER BY [Priority] DESC) as N
FROM dbo.tblAssetLink) AS filteredAssetLink
ON dbo.tblBlog.BID = filteredAssetLink.BID
LEFT OUTER JOIN dbo.tblAssets
ON filteredAssetLink.AID = dbo.tblAssets.AID
WHERE dbo.tblBlog.Deleted = 'False' AND filteredAssetLink.N = 1
ORDER BY tblBlog.DateAdded DESC

Select multiple column query for view by using where clause?

How to get display id and name from a table into view. Where display id select by using where clause, upto now I am select only display id but now I want to select name also from same table.
old table was like this.
SELECT id,
(SELECT displayid
FROM quickpay12.q_sponsortrack AS Q_SponsorTrack_1
WHERE ( f1.transferto = f1.id )) AS TransferTo,
(SELECT displayid
FROM quickpay12.q_sponsortrack AS Q_SponsorTrack
WHERE ( f1.transferby = f1.id )) AS TransferBy,
descid,
credit,
debit,
description,
vdate,
balance,
wallettype,
sno
FROM quickpay12.f_transactionsummary_employee AS f1
Try following query to return all columns from all tables :
SELECT f1.* ,
Q_SponsorTrack_1.* ,
Q_SponsorTrack.*
FROM quickpay12.f_transactionsummary_employee AS f1
LEFT JOIN quickpay12.q_sponsortrack AS Q_SponsorTrack_1 ON f1.transferto = Q_SponsorTrack_1.id
LEFT JOIN quickpay12.q_sponsortrack AS Q_SponsorTrack ON f1.transferby = Q_SponsorTrack.id

SQL JOIN Statement

Lets say I have a table e.g
Request No. Type Status
---------------------------
1 New Renewed
and then another table
Action ID Request No LastUpdated
------------------------------------
1 1 06-10-2010
2 1 07-14-2010
3 1 09-30-2010
How can I join the second table with the first table but only get the latest record from the second table(e.g Last Updated DESC)
SELECT T1.RequestNo ,
T1.Type ,
T1.Status,
T2.ActionId ,
T2.LastUpdated
FROM TABLE1 T1
JOIN TABLE2 T2
ON T1.RequestNo = T2.RequestNo
WHERE NOT EXISTS
(SELECT *
FROM TABLE2 T2B
WHERE T2B.RequestNo = T2.RequestNo
AND T2B.LastUpdated > T2.LastUpdated
)
Using aggregates:
SELECT r.*, re.*
FROM REQUESTS r
JOIN REQUEST_EVENTS re ON re.request_no = r.request_no
JOIN (SELECT t.request_no,
MAX(t.lastupdated) AS latest
FROM REQUEST_EVENTS t
GROUP BY t.request_no) x ON x.request_no = re.request_no
AND x.latest = re.lastupdated
Using LEFT JOIN & NOT EXISTS:
SELECT r.*, re.*
FROM REQUESTS r
JOIN REQUEST_EVENTS re ON re.request_no = r.request_no
WHERE NOT EXISTS(SELECT NULL
FROM REQUEST_EVENTS re2
WHERE re2.request_no = r2.request_no
AND re2.LastUpdated > re.LastUpdated)
SELECT *
FROM REQUEST, ACTION
WHERE REQUEST.REQUESTNO = ACTION.REQUESTNO --Joining here
AND ACTION.LastUpdated = (SELECT MAX(LastUpdated) FROM ACTION WHERE REQUEST.REQUESTNO = ACTION.REQUESTNO);
A sub-query is used to get the last updated record's date and matches against itself to prevent the other records being joined.
Granted, depending on how precise the LastUpdated field is, it can have problems with two records being updated on the same date, but that is a problem encountered in any other implementation, so the precision would have to be increased or some other logic would have to be in place or another distinguishing characteristic to prevent multiple rows being returned.
SELECT r.RequestNo, r.Type, r.Status, a.ActionID, MAX(a.LastUpdated)
FROM Request r
INNER JOIN Action a ON r.RequestNo = a.RequestNo
GROUP BY r.RequestNo, r.Type, r.Status, a.ActionID
We can use the operation Top 1 with ORDER BY clause. For instance, if your tables are RequestTable(ID,Type,Status) and ActionTable(ActionID,RequestID,LastUpdated), the query will be like this:
Select Top 1 rq.ID, rq.Status, at.ActionID
From RequestTable as rq
JOIN ActionTable as at ON rq.ID = at.RequestID
Order by at.LastUpdated DESC