Combining rows by key and expression - sql

I've got a table
email::string
location::string
day_1::boolean
day_2::boolean
...
Now I need to get for each email OR of days. For the following input
user1#gmail.com | location1 | true | false
user1#gmail.com | location2 | false | true
I want to get
user1#gmail.com | true | true

SELECT email, bool_or(day_1) AS day_1, bool_or(day_2) AS day_2 FROM your_table GROUP BY email

Related

How to check whether a user has records in past?

Sample Table
================================================================
id | user_id | certificate_id | is_retraining | created_on
================================================================
1 | 1 | 1 | false | 2021-01-01
2 | 1 | 2 | false | 2021-01-02
3 | 2 | 1 | false | 2021-01-03
4 | 2 | 2 | false | 2021-03-03
5 | 3 | 1 | true | 2021-10-10
6 | 2 | 2 | true | 2021-10-10
Above sample table consists Users info who completed certifications. An user can also go for retraining but he/she should have completed a course before retaking it.
User Id: 2 is retrained on certificate 2, he has a record in past (Completed same certificate earlier), but
User id: 3 has no certificates in past but he directly choose retraining.
How can we identify users who went for retraining without having a certification (Particular certificate) in past?
Ideally im looking for below structure for all retrainings?
=============================================
user_id | certificate_id | has_past_records
==============================================
2 | 2 | true
3 | 1 | false
You could just use LAG() to find out the previous record's value.
If the previous record doesn't exist, LAG() will return NULL by default.
So, the following code identifies three possibilities...
Has never trained before
Is re-training following a previous re-training
Is re-training following a previous initial-training
WITH
history AS
(
SELECT
*,
LAG(is_retraining) OVER (PARTITION BY user_id, certificate_id
ORDER BY created_on
)
AS previous_training_status
FROM
your_table
)
SELECT
user_id,
certificate_id,
CASE
WHEN previous_training_status IS NULL THEN 'never_previously_trained'
WHEN previous_training_status = true THEN 'previously_retrained'
ELSE 'previously_trained'
END
FROM
history
WHERE
is_retraining = true

How to find if user relation exists on another table

I have a table called users and another table called relationship which has a column of two userId. I want to find an output if the user has a relationship with another user, (for this example, it is a user with userId = 2). If they do have a relationship, I want my output to be true, else false. I am having some trouble and wondering if anyone can help me.
I tried something like this:
SELECT DISTINCT
userid,
CASE WHEN user_one_id = '2' THEN true ELSE false END AS has_user_two
FROM users
LEFT JOIN relationship ON userid = user_two_id;
However, I am getting duplicates...
My Query output that is wrong
userid | has_user_two|
---------------------+
1 | true |
1 | false |
2 | false |
3 | false |
4 | true |
5 | true |
Users
userid
-----------
1
2
3
4
5
relationship
user_one_id| user_two_id
-----------+-------------
1 | 1
3 | 1
3 | 2
My output should look something like...
userid | has_user_two|
---------------------+
1 | true |
2 | false |
3 | false |
4 | false |
5 | false |
Any help would be appreciated.
Use EXISTS:
SELECT u.userid,
(EXISTS (SELECT 1
FROM relationship r
WHERE r.user_one_id = 2 AND r.user_two_id = u.userid
)
) as has_user_two
FROM users u;
Note that you don't need a CASE expression in Postgres. A boolean expression can be -- well -- a boolean column.

Setting value of boolean columns based on existence of value in set

I have a SQL table of the format (INTEGER, json_array(INTEGER)).
I need to return results from the table that have two boolean columns. One is set to true iff a 1 appears in the json_array, and the other true iff a two appears in the array. Obviously there is not mutual exclusion.
For example, if the data were this:
-------------------------------
| ID | VALUES |
-------------------------------
| 12 | [1, 4, 6, 11] |
_______________________________
| 74 | [0, 1, 2, 5] |
-------------------------------
I would hope to get back:
-------------------------------
| ID | HAS1 | HAS2 |
-------------------------------
| 12 | true | false |
_______________________________
| 74 | true | true |
-------------------------------
I have managed to extract the json data out of the values column using json_each, but am unsure how to proceed.
If I recall correctly, SQLite max aggregate function supports boolean, therefore you can simply group by your data:
select
t1.id,
max(case json_each.value when 1 then true else false end) as has1,
max(case json_each.value when 2 then true else false end) as has2
from
yourtable t1,
json_each(t1.values)
group by
t1.id

SQL Query (Display All 'x' Where 'x' Is Not In Table '2' for field 'y' and has 'z' flag)

I need to return all 'contacts' that do not appear in the 'delegate' table for 'event name' but do have flags in the 'contacts' table that can selected by the user for the search.
I know the query can be broken in to 2 parts.
Are they already attending this event (Does their email appear in 'delegates' table with delegates.event field matching 'event' on the user form)
WHERE (
d.Event <> [Forms]![usf_FindCampaignContacts]![FCC_EventName]
Do they match the criteria (Have they got the HR flag in 'contacts' table)
AND (c.[HR-DEL] = [Forms]![usf_FindCampaignContacts]![FCC_HRD] OR IsNull([Forms]![usf_FindCampaignContacts]![FCC_HRD]));
Based on the 2 things that the query is required to do I have written the following code...
SELECT
c.[First Name], c.[Last Name], c.Email, d.Event, c.Suppress, c.[HR-DEL]
FROM tbl_Contacts AS c LEFT JOIN tbl_Delegates AS d ON c.Email = d.Email
WHERE (
d.Event <> [Forms]![usf_FindCampaignContacts]![FCC_EventName]
And
c.Suppress = False
)
AND (c.[HR-DEL] = [Forms]![usf_FindCampaignContacts]![FCC_HRD] OR IsNull([Forms]![usf_FindCampaignContacts]![FCC_HRD]));
[FCC_HRD] refers to the user selected input on the form, I tried to use a <> to remove matching records but I feel this is where the compile error is so I changed these to and/or statements and this part now returns results with the matching flags (Success)
Other issue with attempting to do it this way is even if it worked it would remove anyone who was listed in the delegates/sponsor table. Which is why I added the <> statement for the Event as it only needs to remove them off the list for the named event. Again this works perfectly well (Success)
Final issue is the results are clearly being pulled from the 'delegates' table not the 'contacts' table as both parts above work but only display the results that match criteria in delegates table not from contacts.
Here is the query/table relationships
Here is the user form (This is not the final design)
Below are the 3 tables that are used in the query (2 direct, 1 linked)
Contacts (c)
+----+------------+---------------+-------------------------+--------+----------+
| ID | First Name | Last Name | Email | HR-DEL | Suppress |
+----+------------+---------------+-------------------------+--------+----------+
| 1 | A | Platt | a.platt#fake.com | TRUE | TRUE |
| 2 | D | Farr | d.farr#fake.com | TRUE | FALSE |
| 3 | Y | Helle | y.helle#fake.com | TRUE | FALSE |
| 4 | S | Oliphant | soliphant#fake.com | TRUE | FALSE |
| 5 | J | Bedell-Pearce | jbedell-pearce#fake.com | TRUE | FALSE |
| 6 | J | Walker | j.walker#fake.com | FALSE | FALSE |
| 7 | S | Rug | s.rug#fake.com | FALSE | FALSE |
| 8 | D | Brown | d.brown#fake.com | FALSE | FALSE |
| 9 | R | Cooper | r.cooper#fake.com | TRUE | FALSE |
| 10 | M | Morrall | m.morrall#fake.com | TRUE | FALSE |
+----+------------+---------------+-------------------------+--------+----------+
Delegates (d)
+----+-------------------------+-------+
| ID | Email | Event |
+----+-------------------------+-------+
| 1 | a.platt#fake.com | 2 |
| 2 | d.farr#fake.com | 1 |
| 3 | y.helle#fake.com | 4 |
| 4 | soliphant#fake.com | 3 |
| 6 | jbedell-pearce#fake.com | 2 |
+----+-------------------------+-------+
Events (not direct but used to check event name drop-down on user form vs event number in delegates)
+----+------------+
| ID | Event Name |
+----+------------+
| 1 | Test 1 |
| 2 | Test 2 |
| 3 | Test 3 |
| 4 | Test 4 |
+----+------------+
Based on form selection and this sample data I need to return the following:
All contacts who are flagged 'HR' TRUE, not suppressed or going to event named 'test 2' (Should be 5 - I always return the names of 'delegates' not going to the event only = 3)
Final results should be:
+----+------------+-----------+--------------------+--------+----------+
| ID | First Name | Last Name | Email | HR-DEL | Suppress |
+----+------------+-----------+--------------------+--------+----------+
| 2 | D | Farr | d.farr#fake.com | TRUE | FALSE |
| 3 | Y | Helle | y.helle#fake.com | TRUE | FALSE |
| 4 | S | Oliphant | soliphant#fake.com | TRUE | FALSE |
| 9 | R | Cooper | r.cooper#fake.com | TRUE | FALSE |
| 10 | M | Morrall | m.morrall#fake.com | TRUE | FALSE |
+----+------------+-----------+--------------------+--------+----------+
At the moment it appears to be pulling results from the wrong table (d not c). I attempted to change to OUTER join type but that returned with a FROM syntax error.
If I understand it correctly, basically you want to do this:
SELECT A.foo
FROM A
LEFT JOIN B
ON A.bar = B.bar
WHERE
<complex condition, partly involving B>
This cannot work. By including B in the global WHERE condition, you turn the LEFT JOIN into an INNER JOIN, and so you will only ever get records that match between A and B.
You can either move the filter on B into the JOIN condition:
SELECT A.foo
FROM A
LEFT JOIN B
ON (A.bar = B.bar)
AND (B.bamboozle = 42)
WHERE
A.columns = things
or LEFT JOIN a filtered subquery:
SELECT A.foo
FROM A
LEFT JOIN
(SELECT bar, columns FROM B
WHERE B.bamboozle = 42) AS B1
ON A.bar = B1.bar
WHERE
A.columns = things
So in your query, this is the bamboozle part you will need to move:
d.Event <> [Forms]![usf_FindCampaignContacts]![FCC_EventName]

Expression evaluated to TRUE does not take affect in WHERE clause

Take a look at the following three queries. I cannot understand how a condition that evaluates to TRUE will not return rows when attached to where clause. I expect to get User1 in the second query, as the first query shows that the condition evaluates to TRUE.
cr> select full_name, labels, not 'autogenerated' = ANY(labels), not 'autogenerated' = ANY(labels) or labels = [] from testdb_master_core_users;
+----------------+-------------------+-------------------------------------+--------------------------------------------------------+
| full_name | labels | (NOT 'autogenerated' = ANY(labels)) | ((NOT 'autogenerated' = ANY(labels)) OR (labels = [])) |
+----------------+-------------------+-------------------------------------+--------------------------------------------------------+
| User2 Lastname | ["otherlabel"] | TRUE | TRUE |
| User3 Lastname | ["autogenerated"] | FALSE | FALSE |
| User1 Lastname | [] | TRUE | TRUE |
+----------------+-------------------+-------------------------------------+--------------------------------------------------------+
SELECT 3 rows in set (0.003 sec)
cr> select full_name, labels, not 'autogenerated' = ANY(labels) from testdb_master_core_users where not 'autogenerated' = ANY(labels);
+----------------+----------------+-------------------------------------+
| full_name | labels | (NOT 'autogenerated' = ANY(labels)) |
+----------------+----------------+-------------------------------------+
| User2 Lastname | ["otherlabel"] | TRUE |
+----------------+----------------+-------------------------------------+
SELECT 1 row in set (0.002 sec)
cr> select full_name, labels, not 'autogenerated' = ANY(labels) from testdb_master_core_users where not 'autogenerated' = ANY(labels) or labels = [];
+----------------+----------------+-------------------------------------+
| full_name | labels | (NOT 'autogenerated' = ANY(labels)) |
+----------------+----------------+-------------------------------------+
| User2 Lastname | ["otherlabel"] | TRUE |
| User1 Lastname | [] | TRUE |
+----------------+----------------+-------------------------------------+
SELECT 2 rows in set (0.002 sec)
Your expectation is right - the second query should also return User1.
This behaviour is caused by the fact that the expressions in the select are evaluated differently than the one in the where clause. The latter, which utilizes the underlying lucene index, seems to do a wrong conversion of NOT which prevents the empty list from being found.
This issue will be fixed with the upcoming releases 1.0.6 and 1.1.1.