querying data with sqlite - sql

I have data in an sqlite db that contains the following columns:
date | name | id | code
all as TEXT (I sourced it from a csv file) and I want to build a query that finds all names that have code ABC120 but not ABC306 nor ABC305 on the same date and group the result GROUP BY name.
How do I do this?

If you want to use GROUP BY you must group by name, date first and set the conditions in the HAVING clause, but also you must use DISTINCT so the results do not contain duplicate names:
select distinct name
from tablename
group by name, date
having sum(code = 'ABC120') > 0 and sum(code in ('ABC305', 'ABC306')) = 0;
You can get the same results with EXISTS:
select distinct t.name
from tablename t
where t.code = 'ABC120'
and not exists (select 1 from tablename where name = t.name and date = t.date and code in ('ABC305', 'ABC306'))

You can use having:
select date, name
from t
where code in ('ABC120', 'ABC306', 'ABC305')
group by date, name
having min(code) = 'ABC120' and max(code) = 'ABC120';
Note: because of the three codes you chose, you could just use max(code) = 120. However, that does not generalize to other code values.

Related

How to include column not included in Group By

I have the table DirectCosts with the following columns:
DetailsID (unique)
InvoiceNumber
ProjectID
PayableID
I need to find the duplicates combinations of payableid and invoicenumber.
How can I adjust the following query so that it accommodates the combination AND displays the list of instead of the count?
SELECT sinvoicenumber, count(*)
FROM exportdirectcostdetails where iprocoreprojectid = 1187294
GROUP BY sinvoicenumber
HAVING COUNT(*) > 2
Is there a way it can display all columns?
Original Question : Why do I get error ed2 should have column name defined
You are having a derived table, so you need to have column names for the derived table.
select ed1.sinvoicenumber,
ed1.ipayableid,
ed2.sinvoicenumber
from ExportDirectCostDetails ed1
inner join
(
SELECT sinvoicenumber, count(sinvoicenumber) AS InvoiceNumberCount
FROM exportdirectcostdetails
where iprocoreprojectid = 1187294
GROUP BY sinvoicenumber
HAVING COUNT(*) > 2
) ed2
on ed1.sinvoicenumber = ed2.sinvoicenumber
Updated Question: How to have all column names
You need to have PARTITION BY clause defined and then apply filter as given below:
SELECT t.* FROM
(SELECT *, count(*) OVER(PARTITION BY payableid,invoiceNumber) AS InvoiceCount
FROM exportdirectcostdetails where iprocoreprojectid = 1187294) as t
WHERE InvoiceCount > 1

Adding new column of total_event

I want to append virtual column in SELECT result with the name of total_event which will be total of same type of wait_event_type, As shown in the screenshot I want to sum 'Lock' which will be 18+2 = 20 and add that against all Lock type column.
I have a event_stats table with three columns wait_event_type, wait_event, event_count which holds all the data.
You can use a window function to do this:
SELECT
wait_event_type,
wait_event,
event_count,
SUM(event_count) OVER (PARTITION BY wait_event_type) AS total_event_count
FROM my_table
You can also use group by clause and join
select m.wait_event_type,
m.wait_event,
m.event_count,
t.total_event_count from (select wait_event_type,SUM(event_count) as total_event_count
from my_table group by wait_event_type)t join my_table m on
m.wait_event_type=t.wait_event_type

How to write a SQL-Query for the following table?

My table is defined like this:
Name is a string and property too.
ID | Name | Property
An example for data in this table is this:
ID | Name | Property
1 Peter Newsletter
2 Paul Register
3 Peter Register
4 Shaun Newsletter
5 Steve Register
Now I like to query all people that have the property newsletter and register.
As a result I should get Peter, because he has both property's.
So the resulting table should be like:
ID | Name | Property
1 Peter Newsletter
3 Peter Register
So everything I try to query is which person has both property's newsletter and register.
Here is one method:
select t.*
from table t
where exists (select 1
from table t2
where t2.name = t.name and t2.property = 'NewsLetter'
) and
exists (select 1
from table t2
where t2.name = t.name and t2.property = 'Register'
);
If you just want the list of names, perhaps with ids, I would do that as:
select t.name
from table t
where t2.property in ('NewsLetter', 'Register')
group by t.name
having count(distinct property) = 2;
How you get the list of ids depends on your database, something like listagg() or group_concat() or string_agg().
An alternative, pretty much on the same lines as Gordon's solution, but without using EXISTS:
select * from tablename
where name in (select name from tablename where property = 'Newsletter')
and name in (select name from tablename where property = 'Register')
One more way:
SELECT * FROM T as T1
WHERE Property IN ('Newsletter','Register')
AND EXISTS (SELECT * FROM T
WHERE Name=T1.Name
and Property IN ('Newsletter','Register')
and Property <> T1.Property
)
SQLFiddle demo
Another one, for the record
WITH cteHasBoth
as (select Name
from MyTable
where Property in ('Newsletter', 'Register')
group by Name
having count(*) = 2)
select ID, Name
from MyTable
where name in (select Name from cteHasBoth)
This would require only two sacns through the table.
It's hard to be sure without knowing more about the data. Given the exact requirements that you gave to us, this will give the results you showed:
WITH multprop (multName) AS (
SELECT NAME FROM myTable
WHERE Property IN('Newsletter','Register')
GROUP BY NAME
HAVING count(*)>1 )
select id, Name, Property
from multprop inner join myTable
on multName = Name
But minor differences in your requirements will mess things up. For example, will there ever be Property values other than the two you listed? Or can a Name show up multiple times with the same Property?
EDIT: The added WHERE clause limits rows in the CTE to the requested specific set of Property values. This is from the more detailed requirements in comments.

using group by with condition in oracle

I have two situations in my query , One where I need to use group by clause and other where i do Not want to use group by
So in below query If Name = Map .. then use group by..like this (Means show Only distinct Id's)
select max(start_time),id,name from workitem where ( NAME = 'Map' or NAME = 'Validate') group by id,name;
But if in the above query when Name Not equal 'Map' then DO NOT use group by..like this (Means show all id's even duplicates)
select start_time,id,name from workitem where ( NAME = 'Map' or NAME = 'Validate');
How can i achieve this with one query
select max(start_time),id
from workitem where ( NAME = 'Map' or NAME = 'Validate')
group by id,name
UNION ALL
select start_time,id
from workitem
where NAME <> 'Map';

SQL get rows matching ALL conditions

I would like to retrieve all rows matching a set of conditions on the same column. But I would like the rows only if ALL the conditions are good, and no row if only one condition fails.
For example, taking this table:
|id|name|
---------
|1 |toto|
|2 |tata|
I would like to be able to request if "tata" && "toto" are in this table. But when asking if "tata" and "tuto" are in, I would like an empty response if one of argument is in not in the table, for example asking if "toto" && "tutu" are included in the table.
How can I do that ?
Currently, I'am doing one query per argument, which is not very efficient. I tried several solutions including a subselect or a group+having, but no one is working like I want.
thanks for your support !
cheers
This isn't the most efficient way, but this query would work.
SELECT * FROM table_name
WHERE (name = 'toto' OR name = 'tata')
AND ( SELECT COUNT(*) FROM table_name WHERE name = 'toto') > 0
AND ( SELECT COUNT(*) FROM table_name WHERE name = 'tata') > 0
This is a little vague. If the names are unique, you could count the matching rows that match a where clause:
where name='toto' or name='tata'
If the count is 2, then you know both matched. If name is not unique you could potentially select the first ID (select top 1 id ...) that matches each in a union and count those with an outer select.
Even if you had an arbitrary number of names to match, you could create a stored procedure or code in whatever top-level language you are using to build the select statement.
SELECT 1 AS found FROM hehe
WHERE 1 IN (SELECT 1 FROM hehe WHERE name='tata')
AND 1 IN (SELECT 1 FROM hehe WHERE name='toto')
If name is unique you can simplify to:
SELECT *
FROM tbl
WHERE name IN ('toto', 'tata')
AND (SELECT count(*) FROM tbl WHERE name IN ('toto', 'tata')) > 1;
If it isn't:
SELECT *
FROM tbl
WHERE name IN ('toto', 'tata')
AND EXISTS (SELECT * FROM tbl WHERE name = 'toto')
AND EXISTS (SELECT * FROM tbl WHERE name = 'tata');
Or, in PostgreSQL, MySQL and possibly others:
SELECT *
FROM tbl
WHERE name IN ('toto', 'tata')
AND (SELECT count(DISTINCT name) FROM tbl WHERE name IN ('toto', 'tata')) > 1;