posgresql selecting two different data as two columns from one column - postgresql

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');

Related

Make sure every distinct value of Column1 has a row with every distinct value of Column2, by populating a table with 0s - postgresql

Here's a crude example I've made up to illustrate what I want to achieve:
table1:
| Shop | Product | QuantityInStock |
| a | Prod1 | 13 |
| a | Prod3 | 13 |
| b | Prod2 | 13 |
| b | Prod3 | 13 |
| b | Prod4 | 13 |
table1 becomes:
| Shop | Product | QuantityInStock |
| a | Prod1 | 13 |
| a | Prod2 | 0 | -- new
| a | Prod3 | 13 |
| a | Prod4 | 0 | -- new
| b | Prod1 | 0 | -- new
| b | Prod2 | 13 |
| b | Prod3 | 13 |
| b | Prod4 | 13 |
In this example, I want to represent every Shop/Product combination
every Shop {a,b} to have a row with every Product {Prod1, Prod2, Prod3, Prod4}
QuantityInStock=13 has no significance, I just wanted a placeholder number :)
Use a calendar table cross join approach:
SELECT s.Shop, p.Product, COALESCE(t1.QuantityInStock, 0) AS QuantityInStock
FROM (SELECT DISTINCT Shop FROM table1) s
CROSS JOIN (SELECT DISTINCT Product FROM table1) p
LEFT JOIN table1 t1
ON t1.Shop = s.Shop AND
t1.Product = p.Product
ORDER BY
s.Shop,
p.Product;
The idea here is to generate an intermediate table containing of all shop/product combinations via a cross join. Then, we left join this to table1. Any shop/product combinations which do not have a match in the actual table are assigned a zero stock quantity.

Flattenning the Left Join outcome in 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.

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?

query count of rows where id is less than a series of values in Redshift

I have a table etl_control which stores latest_id of x_data table everyday. Now I have a requirement to get the number of rows for each day.
My idea is to run a query to get the count based on a condition x_data.id <= etl_control.latest_id for everyday and get the count.
The table structures are as follows.
etl_control:
record_date | latest_id |
---------------------------------
2016-11-01 | 55 |
2016-11-02 | 125 |
2016-11-03 | 154 |
2016-11-04 | 190 |
2016-11-05 | 201 |
2016-11-06 | 225 |
2016-11-07 | 287 |
x_data:
id | value |
---------------------------------
10 | xyz |
11 | xyz |
21 | xyz |
55 | xyz |
101 | xyz |
108 | xyz |
125 | xyz |
142 | xyz |
154 | xyz |
160 | xyz |
166 | xyz |
178 | xyz |
190 | xyz |
191 | xyz |
The end result should have the number of rows in x_data for each day. I tried a number of variations using JOIN, WITH and COUNT(*) OVER. But the biggest hurdle is to iteratively compare x_data.id with etl_control.latest_id.
Really sorry folks. Got the answer myself after posting the question.
The query is really simple.
WITH data AS (
SELECT e.latest_id
FROM x_data AS x, etl_control AS e
WHERE x.id <= e.latest_id)
SELECT latest_id, count(*) FROM data GROUP BY latest_id;
This basically creates a temp table with latest_id repeated for each row. The latest_id is always greater than or equal to the id from x_data.
A simple group by on this temp table would give the expected result.

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