Flattenning the Left Join outcome in PostgreSQL - postgresql

I have eventtags, filtervalues.So I have something like:
eventtags:
event_id, key_id, value_id, event_date
filtervalues:
value_id, key,value, counts_seen
Let's say I've 2 events reporting with multiple key, value pairs in eventtags table
event_id | key_id | value_id | event_date
---------+--------+----------+-----------
1 | 20 | 32 | xx-xx-xxxx
1 | 21 | 34 | xx-xx-xxxx
2 | 20 | 35 | yy-yy-yyyy
2 | 21 | 39 | yy-yy-yyyy
Corresponding filter_value table is having data as below
values_id | key | value | counts_seen
----------+-------+-------+----------
32 | type | staff | 52
34 | tag | tag1 | 13
35 | type | user | 10
39 | tag | tag2 | 35
Now based on this I tried below query to consolidate the data from two tables
SELECT t.event_id as Event_Id,
DATE (t.event_date) as Event_Date,
v.key as Keys,
v.value as Values
FROM eventtags t
LEFT JOIN filtervalues as v ON t.value_id = v.id
This results in something like this
Event_Id | Keys | Values | Event_Date
---------+--------+----------+-----------
1 | type | staff | xx-xx-xxxx
1 | tag | tag1 | xx-xx-xxxx
2 | type | user | yy-yy-yyyy
2 | tag | tag2 | yy-yy-yyyy
I want the data to be in the below format
Event_Id | type | tag | Event_Date
---------+--------+---------+-----------
1 | staff | tag1 | xx-xx-xxxx
2 | user | tag2 | yy-yy-yyyy
What changes do I need to make on the query above to obtain this format?
Note: I cannot use Pivots since the system I'm working on, doesn't support them.
Any help is much appreciated

Try this for your scenario without pivot(crosstab):
SELECT t.event_id as Event_Id,
max(v.value) filter (where v.key='type') as "type",
max(v.value) filter (where v.key='tag') as "tag",
DATE (t.event_date) as Event_Date
FROM eventtags t
LEFT JOIN filtervalues as v ON t.value_id = v.id
group by t.event_id,t.event_date
DEMO
above will work only for PostgreSQL 9.4 and above.

Related

posgresql selecting two different data as two columns from one column

I need to select two id's from stockcurrent as two different columns (id1,id2), first where points.id = '244' and second where points.id ='191'. But result facing last where clause and filling only one column based on that statement.
I think I've faced a similar problem as in that case: Two SELECT statements as two columns
The only difference is that in the case above his last where clause is in range but mine is not. In my opinion, it is the reason why my statement is not working:
select
(case when po.id='244' then st.id end) id1,
(case when po.id='191' then st.id end) id2
from stockcurrent st
inner join points po on po.id = st.point
where po.id ='244';
My result:
Expected result:
So I need to find a solution to fill both columns with id's not only one which in that case giving me the result(s) of '244'. Thanks in advance.
Example of stockcurrent table:
+-------+-------+
| id | point |
+-------+-------+
| 23414 | 191 |
| 12493 | 191 |
| 16121 | 170 |
| 24325 | 191 |
| 51232 | 244 |
| 11255 | 244 |
| 56572 | 244 |
| 16123 | 170 |
+-------+-------+
Example of points table:
+-----+------+------+
| id | comp | type |
+-----+------+------+
| 191 | 96 | 2 |
| 307 | 96 | 1 |
| 244 | 97 | 0 |
| 311 | 98 | 0 |
| 170 | 109 | 0 |
+-----+------+------+
Change the query to:
select
(case when po.id='244' then st.id end) id1,
(case when po.id='191' then st.id end) id2
from stockcurrent st
inner join points po on po.id = st.point
where po.id in ('244', '191');

How to keep related groups together?

DB fiddle DB fiddle (updated)
I pay attention to 1-2; 3-4 cases. Notice, that all rows from config_id group still together with all rows of xgroup
Detailed task description:
I have some order details for some resource. For each ordered resource there should be allocated resource. Resource may belongs to each other and belongs to some group. Consider virtual machine VM has: RAM, CPU, HDD.
Currently relation between orders and allocated resources is broken. I try to write query to analyze what is ordered without allocated resource and what is allocated without order.
CREATE TABLE order_detail (
id SERIAL,
order_id INTEGER,
resource_type_id INTEGER,
allocated_resource_id INTEGER,
amount INTEGER
)
CREATE TABLE allocated_resource (
id SERIAL,
group_id INTEGER,
resource_type_id INTEGER,
resource_uuid UUID,
)
This is easily done:
select * from order_detail od
where od.allocated_resource_id IS NULL
SELECT * FROM allocated_resource ar
WHERE NOT EXISTS ( SELECT 1 FROM order_detail od where od.allocated_resource_id = ar.id)
But I need to found to which Order assign that allocated resource. Or which resource allocate for this Order. Or which Order bind to allocated resource.
Data example:
id | order_id | allocated_resource_id | resource_type_id
--------------------------------------------------------
41 | 1 | 1 | 70
42 | 1 | | 71
43 | 1 | | 73
44 | 2 | | 70
45 | 2 | 5 | 71
id | group_id | resource_type_id
--------------------------------
1 | 1 | 70
2 | 1 | 71
3 | 1 | 72
4 | 2 | 70
5 | 2 | 71
6 | 2 | 73
Here I want to get:
id | order_id | allocated_resource_id | resource_type_id | ar.id | ar.group_id | ar.resource_type_id
----------------------------------------------------------------------------------------------------
41 | 1 | 1 | 70 | 1 | 1 | 70
42 | 1 | | 71 |
43 | 1 | | 73 |
| | | | 1 | 1 | 71
| | | | 1 | 1 | 72
44 | 2 | | 70 |
45 | 2 | 5 | 71 | 5 | 1 | 71
| | | | 4 | 1 | 70
| | | | 6 | 1 | 73
Unfortunately order by ar.id or order by od.id will move unbound order details/allocated resource to bottom. I want to keep order details/allocated resources together as in example above.
To resolve task I select all available related groups first:
od_ar_group AS (
SELECT
od.order_id, ar.group_id,
cast( od.order_id AS TEXT ) || '-' || cast( ar.group_id AS TEXT ) AS odar
FROM order_detail od
FULL JOIN allocated_resource ar ON ar.id = od.allocated_resource_id
WHERE od.order_id IS NOT NULL AND ar.group_id IS NOT NULL
GROUP BY od.order_id, ar.group_id
)
Then I attach group info to both tables:
SELECT od.*, odar.odar
FROM order_detail od
LEFT JOIN od_ar_group odar ON odar.order_id = od.order_id
SELECT ar.*, odar.odar
FROM allocated_resource ar
LEFT JOIN od_ar_group odar ON odar.parent_id = ar.parent_id
Finally I can join those groups and sort inside them. So unbound order detail/allocated resource is inside group and not at the bottom of table:
SELECT
CASE WHEN od.odar IS NOT NULL THEN od.odar ELSE ar.odar END AS odar,
od.*, ar.*
FROM od_grouped
FULL JOIN ar_grouped ar ON ar.odar = od.odar
AND ar.id = od.allocated_resource_id
ORDER BY odar, CASE WHEN od.id IS NULL THEN 1 WHEN ar.id IS NULL THEN 2 ELSE 0 END, od.id NULLS LAST
Is there a more easy way to keep related rows inside their group?

PostgreSQL: Creating a new view by filtering rows based on column values in numerous rows

I am working with a magento table like this:
+---------------------------------------------------------------------------------+
| date product_name product_id product_type time order_id qty_ordered last_order |
+---------------------------------------------------------------------------------+
| 2017/2/15 X 18W1 custom 1900 12 1 2016/12/10 |
| 2017/2/15 X 18W1 simple 1900 12 1 2016/12/3 |
| 2017/2/15 XX 18W2 simple 1900 12 3 2016/12/4 |
| 2017/2/20 Y 22Y34 simple 1532 19 1 2017/1/9 |
| 2017/2/20 Z 22Y35 simple 1532 19 2 2017/1/15 |
| 2017/2/20 Z 22Y35 custom 1532 19 2 2016/9/12 |
+---------------------------------------------------------------------------------+
I want to make a new view, by first looking for rows which have the same order_id and product_id. Then out of the two rows, I want to only take the row where product_type = "custom". I want to also only take certain columns.
So my final table after doing this operation from aboveshould look like this:
+-----------+--------------+------------+--------------+----------+-------------+
| date | product_name | product_id | product_type | order_id | qty_ordered |
+-----------+--------------+------------+--------------+----------+-------------+
| 2017/2/15 | X | 18W1 | custom | 12 | 1 |
+-----------+--------------+------------+--------------+----------+-------------+
| 2017/2/15 | XX | 18W2 | simple | 12 | 3 |
+-----------+--------------+------------+--------------+----------+-------------+
| 2017/2/20 | Y | 22Y34 | simple | 19 | 1 |
+-----------+--------------+------------+--------------+----------+-------------+
| 2017/2/20 | Z | 22Y35 | custom | 19 | 2 |
+-----------+--------------+------------+--------------+----------+-------------+
So far, I've tried using the following query to no avail:
IF EXISTS (SELECT 1 FROM table GROUP BY order_id, product_id HAVING "count"(*)>1;) THEN
SELECT table.date, table.product_name, table.product_id, table.product_type, table.order_id, table.qty_ordered
WHERE product_type = "configurable" FROM table;
ELSE SELECT SELECT table.date, table.product_name, table.product_id, table.product_type, table.order_id, table.qty_ordered FROM table;
END IF;
Any assistance would be greatly appreciated, thank you!
You could do this by selecting all the custom entries, and then selecting those simple entries where there is not a corresponding custom entry. Something like:
create view v_tab
as
select * from tab where product_type = 'custom'
union all
select * from tab t1 where product_type = 'simple' and
not exists
(select * from tab t2
where t2.order_id = t1.order_id
and t2.product_id = t1.product_id
and t2.product_type = 'custom')

T-SQL 2012- How can I pair down query and check the returned values

I have a table which captures various events and returns data as below
+----+-----------+--------------+-----------------+
| ID | EventType | SystemUserID | OrganisationID |
+----+-----------+--------------+-----------------+
| 23 | 8 | 11 | 1 |
| 44 | 7 | 456 | 304 |
| 80 | 1 | 48 | 4042 |
| 89 | 2 | 5673 | 183 |
+----+-----------+--------------+-----------------+
EventType 8 is captured each time a user visits an organisation.
I have another table named OrganisationHasContact as such
+----+----------------+--------------+
| ID | OrganisationID | SystemUserID |
+----+----------------+--------------+
| 23 | 1 | 11 |
| 44 | 304 | 456 |
| 80 | 4042 | 48 |
| 89 | 183 | 5673 |
+----+----------------+--------------+
I have wrote a query in order to find the total number of visits each organisation has had but excluding SystemUsers who are associated to that organisation
SELECT
OrganisationID AS [OrganisationID],
ORG.Name AS [Compayny Name],
Count(OrganisationID) AS [Visits]
FROM [Audit].[EventData]
LEFT OUTER JOIN Employed.Organisation AS ORG ON [EventData].OrganisationID = ORG.ID
Where Not Exists(
Select * From [Audit].[EventData] AS A2
Inner join Employed.OrganisationHasContact AS OHC On [EventData].OrganisationIDID = OHC.OrganisationID
Where OHC.SystemUserID = [EventData].SystemUserID
)
AND
EventTypeID = 8
Group BY [EventData].OrganisationID,
ORG.Name
Order By Visits Desc
To test the above query was returning correct values (449 visits) I did the following
First I ran this query to get all SystemUserId's associated to Org 1741
Select * from Employed.OrganisationHasContact
Where OrganisationID = 1741
Then with the returned SystemUserID's I ran this query
SELECT Distinct
OrganisationID AS [OrganisationID],
ORG.Name AS [Compayny Name],
Count(OrganisationID) AS [Visits]
FROM [Audit].[EventData]
LEFT OUTER JOIN Employed.Organisation AS ORG ON [EventData].OrganisationID = ORG.ID
Where
EventTypeID = 8
AND SystemUserID NOT IN (35, 4602, 48, 4603, 7704)
Group BY OrganisationID,
ORG.Name
Order By Visits Desc
This Returned 446 visits for Org 1741, my original query returns 449 visits.
What could be causing the difference?
Can I improve my original query somehow?
Is there a better way to test this?
Thanks

Grouping in t-sql with latest dates

I have a table like this
Event ID | Contract ID | Event date | Amount |
----------------------------------------------
1 | 1 | 2009-01-01 | 100 |
2 | 1 | 2009-01-02 | 20 |
3 | 1 | 2009-01-03 | 50 |
4 | 2 | 2009-01-01 | 80 |
5 | 2 | 2009-01-04 | 30 |
For each contract I need to fetch the latest event and amount associated with the event and get something like this
Event ID | Contract ID | Event date | Amount |
----------------------------------------------
3 | 1 | 2009-01-03 | 50 |
5 | 2 | 2009-01-04 | 30 |
I can't figure out how to group the data correctly. Any ideas?
Thanks in advance.
SQL 2k5/2k8:
with cte_ranked as (
select *
, row_number() over (
partition by ContractId order by EvantDate desc) as [rank]
from [table])
select *
from cte_ranked
where [rank] = 1;
SQL 2k:
select t.*
from table as t
join (
select max(EventDate) as MaxDate
, ContractId
from table
group by ContractId) as mt
on t.ContractId = mt.ContractId
and t.EventDate = mt.MaxDate