using group by with condition in oracle - sql

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

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

querying data with sqlite

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.

Optimize SQL query using arrays

My sql report has lots of inner queries. I have to pass the list of values in where clause. Same values are being passed few times. It takes more than 10 minutes to execute this query. Is there any way to optimise replacing the where condition with array or some other mechanism.
This list of IDs are used multiple times inside the nested queries.
List of IDS= SELECT ID
FROM Employee
where City = 'Berlin'
...............
This is a snippet of my query (not fully copied just wanted to show how I used above list in where conditions)
SELECT Job_id,client_id,details
FROM Clients
where employeedID not in ( ***SELECT ID
FROM Employee
where City = 'Berlin*'**)
where WORKID in (SELECT [WORKID]
FROM Client_projects
where DESCRIPTION in (SELECT [DESCRIPTION]
FROM Projects
where employeedID in (***SELECT ID
FROM Employee
where City = 'Berlin'***)
where taskname = 'Project in Progress'))) and TASKNAME like '%Progress') and description in (SELECT [DESCRIPTION]
FROM Client
where employeeID in (***SELECT ID
FROM Employee
where City = 'Berlin'***
where taskname = 'Project Completed')) and STATUS not in ('Cancelled','Closed')
.........
I tried to create an array to pass the value but couldn't succeed .
I would suggest using common table expression instead of repeating select ID..
with ListOfIDS as (
select ID
from Employee
where City = 'Berlin'
) select *
from otherTable
join ListOfIDS on ListOfIDS.ID = otherTable.ID
...
this simplifies query.
I also suspect what is killing your performance is TASKNAME like '%Progress' as this is not sargable.

SQL - passing variable from first select to second select

I have one table things full of items listed by ItemID. Given an ItemID, I need to get the record with the ItemID and all other items with the same name.
In the sample data below, given the ItemID of 1, I need to select all records with the same name (in this case, "poptarts") as ItemID 1, including the record with ItemID 1.
ItemID = 1 name = poptarts
ItemID = 7 name = poptarts
ItemID = 8 name = cheddar
ItemID = 323 name = poptarts
select a.ItemID, a.name from things where a.ItemID = '1'
UNION
select b.ItemID, b.name from things where b.name = a.name
The SQL I've written above however does not pass a.name to the second select. Is there any way to pass the first name value to the second select? I would like for the statement to return itemid = 1 as the first row and 7 and 323 as the other rows.
UNION is only really used to concatenate two distinct sets. Based on your example, you could probably do something like this:
SELECT a.ItemID, a.Name
FROM things a
WHERE name IN (SELECT name FROM things WHERE itemID = 1)
There are lots of ways to write this kind of query and will depend on which flavor of SQL you're using but this should be more or less universal.
select
a.itemID,
a.name
from
things a
where a.name in (
select name
from things b
where b.itemID = '1'
)
SELECT this.name, this.id, that.id
FROM thing this
LEFT JOIN thing that ON that.name=this.name AND that.id <> this.id
WHERE this.id = 1
;
NOTE: this also selects the this-rows that have no twin records; in that case the that.id will be NULL. If you want to suppress the records without twin-records, remove the LEFT.
UPDATE: added the id <> id clause to suppres the obvious match.
If you really only have one table, no need to bring it in twice, UNION, or anything fancy like htat.
SELECT
name
FROM
a --assuming this is your only table
GROUP BY
itemID, name
HAVING
itemID = '1'

Updating a field based on a count of records from a different table

I need to set a value to 1 in table where the count for a given role in another table is > 1.
The table cursillo.members has fields memid and hsd. Table cursillo.teams has fields memid (the link between the two) a field called movement and another called role.
What I am trying to accomplish is something similar to this:
update cursillo.members_eligible p, cursillo.teams pp
set p.hsd=1
where p.memid = pp.memid AND (pp.role = 'HSD' OR pp.role = 'SD')
and pp.movement = 'Cursillo' AND count(pp.role) > 1;
or this:
update members_eligibile
set hsd=1
from teams
where teams.memid=members_eligible.memid
and (teams.role = 'HSD' OR teams.role = 'SD')
and teams.movement = 'Cursillo'
and count(teams.role) > 1;
In other words if a given memid has more than one record in the cursillo.teams table where the value of the role is equal to either HSD or SD, then set cursillo.members_eligible.hsd to 1.
I can't figure out to handle the count() part.
Thanks,
Mike Reed
Possible duplicate question:
MySQL - Using COUNT(*) in the WHERE clause
Try using the 'having' keyword
Here's the relevant section from the linked answer (in this case, a select statement):
select gid
from `gd`
group by gid
having count(*) > 10
order by lastupdated desc
It looks like 'having' can only be used in select statments though:
http://www.mysqltutorial.org/mysql-having.aspx
So you may need to have your update's where clause include a select statement:
update members_eligibile
set hsd=1
from teams
where teams.memid=members_eligible.memid
and (teams.role = 'HSD' OR teams.role = 'SD')
and teams.movement = 'Cursillo'
and members_eligible.memid IN
(SELECT members_eligible.memid from members_eligible where teams.memid=members_eligible.memid having count(teams.role) > 1);
You will have to adjust the select statement, I haven't tested it
SQL Server 2005+
UPDATE x
SET x.hsd = 1
FROM (SELECT e.hsd, COUNT(*) OVER (PARTITION BY t.role) AS cnt
FROM teams t JOIN members_eligibile e ON t.memid = e.memid
WHERE (t.role = 'HSD' OR t.role = 'SD') AND t.movement = 'Cursillo') x
WHERE x.cnt > 1