I have 3 queries and they work fine. There Queries are:
SELECT SUM(SALES)as NETSALES FROM Sales WHERE DOCREF='1'GROUP BY GEOCODE
above query results :
NETSALES
1
2
3
SELECT SUM(SALES)as FRESHRETURNS FROM Sales WHERE DOCREF='2'GROUP BY GEOCODE
above query results :
FRESHRETURNS
1
2
3
SELECT SUM(SALES)as SALESRETURNS FROM Sales WHERE DOCREF='3'GROUP BY GEOCODE
above query results :
SALESRETURNS
1
2
3
is there any way to combine these statements to get the result as
NETSALES | FRESHRETURNS | SALESRETURNS
1------1-------|-----------1-----------|--------1--------
2------2-------|-----------2-----------|--------2--------
3------3-------|-----------2-----------|--------3--------
You didn't mention if you are using MS Sql Server or Oracle, I am assuming MS :)
Make use of CASE and you can basically build a matrix with the result you want:
CREATE TABLE #t
(
Sale int,
DocRef varchar(1),
GeoCode varchar(1)
)
INSERT INTO #t(Sale, DocRef,GeoCode) VALUES(100, '1', 'A')
INSERT INTO #t(Sale, DocRef,GeoCode) VALUES(120, '1', 'A')
INSERT INTO #t(Sale, DocRef,GeoCode) VALUES(110, '2', 'B')
INSERT INTO #t(Sale, DocRef,GeoCode) VALUES(120, '2', 'B')
INSERT INTO #t(Sale, DocRef,GeoCode) VALUES(100, '3', 'C')
INSERT INTO #t(Sale, DocRef,GeoCode) VALUES(100, '3', 'C')
INSERT INTO #t(Sale, DocRef,GeoCode) VALUES(100, '3', 'A')
SELECT
CASE WHEN DocRef='1' THEN SUM(Sale) ELSE 0 END as NETSALES,
CASE WHEN DocRef='2' THEN SUM(Sale) ELSE 0 END AS FRESHRETURNS,
CASE WHEN DocRef='3' THEN SUM(Sale) ELSE 0 END AS SALESRETURNS
FROM
#t
GROUP BY
GeoCode,
DocRef
DROP TABLE #t
I think this works but I haven't tested. I'm adding a fake ID column, giving it value 'x' and joining the 3 result sets using this new ID:
select t.NETSALES, ta.FRESHRETURNS , tb.SALESRETURNS from
(SELECT 'x' as ID, SUM(SALES)as NETSALES FROM Sales WHERE DOCREF='1'GROUP BY GEOCODE,ID ) as t
inner join
(SELECT 'x' as ID, SUM(SALES)as FRESHRETURNS FROM Sales WHERE DOCREF='2'GROUP BY GEOCODE,ID) ta on ta.ID=t.ID
inner join
(SELECT 'x' as ID SUM(SALES)as SALESRETURNS FROM Sales WHERE DOCREF='3'GROUP BY GEOCODE,ID ) tb on tb.ID=t.ID
Probably terribly inefficient but works for me on Oracle
SELECT (SELECT SUM(SALES) FROM Sales WHERE DOCREF='1'GROUP BY GEOCODE) NETSALES,
(SELECT SUM(SALES) FROM Sales WHERE DOCREF='2'GROUP BY GEOCODE) FRESHRETURNS ,
(SELECT SUM(SALES) FROM Sales WHERE DOCREF='3'GROUP BY GEOCODE) SALESRETURNS FROM DUAL
Depending on which database product you are using, you may need to tweak this a bit, but something like this should work for you:
SELECT GEOCODE, SUM(NETSALES), SUM(FRESHRETURNS), SUM(SALESRETURNS)
FROM
(
SELECT GEOCODE, SUM(SALES)as NETSALES, 0 AS FRESHRETURNS, 0 AS SALESRETURNS FROM Sales WHERE DOCREF='1'GROUP BY GEOCODE
UNION ALL
SELECT GEOCODE, 0 AS NETSALES, SUM(SALES)as FRESHRETURNS, 0 AS SALESRETURNS FROM Sales WHERE DOCREF='2'GROUP BY GEOCODE
UNION ALL
SELECT GEOCODE, 0 AS NETSALES, 0 AS FRESHRETURNS, SUM(SALES)as SALESRETURNS FROM Sales WHERE DOCREF='3'GROUP BY GEOCODE
) AS salesData
GROUP BY GEOCODE
Related
I have a product table as below.
Where I want to get each product detail where its product_ship_flag is "YES" for all the products of same the order_number. If any of the product_ship_flag is "No" then the whole order_number should not be in the output. If all product_ship_flag as "No" then should not be in the output.
The Output will look like:
Thanks in advance.
Edited: Few members are not even trying to understand the problem, And some are not able to answer the problem so devoting the question. Please show some sportiness.
Try this.
If the inner query does not return anything for that order that means all the product has flag_ship equal to Yes
select * from product p
where not exists (
select '1' from product p2
where p2.order_number = p1.order_number
and p2.product_ship_flag = 'No')
Isn't that a basic query like this works?
Select * from product where product_ship_flag = 'Yes' group by order_number
Try with this query:
select * from product where orderno not in (select orderno, count(case when product_ship_flaf='No' then 1 end) from product
group by orderno
having count(case when product_ship_flaf='No' then 1 end)>=1)A
#irfan_m, the logic can be captured with the MIN operator. When you do a subquery and using a column called flag for example. You can easily pull out the orders based on your requirement.
See a mock up below:
DECLARE #Producttbl TABLE (id int, order_number varchar(20), product_id varchar(20), stock_cnt int, product_ship_flag VARCHAR(3))
INSERT INTO #Producttbl
SELECT 1,'001','SKU1', 1, 'Yes' union all
SELECT 2,'001','SKU2', 2, 'Yes' union all
SELECT 3,'001','SKU3', 1, 'No' union all
SELECT 4,'002','SKU1', 1, 'Yes' union all
SELECT 5,'002','SKU2', 2, 'Yes' union all
SELECT 6,'003','SKU1', 1, 'No' union all
SELECT 7,'003','SKU2', 2, 'No'
SELECT *
FROM
#Producttbl P
JOIN (
SELECT order_number, Flag=MIN(product_ship_flag)
--product_ship_flag is
---"YES" : for all the products of same the order_number
--If any of the product_ship_flag is "No" then the whole order_number should not be in the output.
--If all product_ship_flag as "No" then should not be in the output.
FROM
#Producttbl
GROUP BY
order_number
)S ON
S.order_number=P.order_number
WHERE
S.Flag='Yes'
see result below:
A left join could be handy in this case.
DECLARE #ProducttblTEST TABLE (id int, order_number varchar(20), product_id
varchar(20), stock_cnt int, product_ship_flag VARCHAR(3))
INSERT INTO #ProducttblTEST
SELECT 1,'001','SKU1', 1, 'Yes' union all
SELECT 2,'001','SKU2', 2, 'Yes' union all
SELECT 3,'001','SKU3', 1, 'No' union all
SELECT 4,'002','SKU1', 1, 'Yes' union all
SELECT 5,'002','SKU2', 2, 'Yes' union all
SELECT 6,'003','SKU1', 1, 'No' union all
SELECT 7,'003','SKU2', 2, 'No'
select * from #ProducttblTEST a
left join (select * from #ProducttblTEST where product_ship_flag = 'no') b on
a.order_number = b.order_number
where a.product_ship_flag = 'yes' and b.order_number is null
I am using Oracle (SQL Developer). Please find below the example and an outcome which would like to get (purpose of select is to find out people who submitted project A and have not done any activities in project B yet):
Data table:
CREATE TABLE "XXX"."TABLE1"
( "STATUS" VARCHAR2(20 BYTE),
"PROJECT_NAME" VARCHAR2(20 BYTE),
"VERSION_NUMBER" NUMBER,
"PERSON" VARCHAR2(20 BYTE)
);
Insert into XXX.TABLE1 (STATUS,PROJECT_NAME,VERSION_NUMBER,PERSON) values ('SUBMITTED','A','0','PETER');
Insert into XXX.TABLE1 (STATUS,PROJECT_NAME,VERSION_NUMBER,PERSON) values ('SUBMITTED','A','0','JOHN');
Insert into XXX.TABLE1 (STATUS,PROJECT_NAME,VERSION_NUMBER,PERSON) values ('SUBMITTED','A','1','JOHN');
Insert into XXX.TABLE1 (STATUS,PROJECT_NAME,VERSION_NUMBER,PERSON) values ('NEW','A','2','JOHN');
Insert into XXX.TABLE1 (STATUS,PROJECT_NAME,VERSION_NUMBER,PERSON) values ('SUBMITTED','A','0','MARY');
Insert into XXX.TABLE1 (STATUS,PROJECT_NAME,VERSION_NUMBER,PERSON) values ('SUBMITTED','B','0','PETER');
Insert into XXX.TABLE1 (STATUS,PROJECT_NAME,VERSION_NUMBER,PERSON) values ('NEW','B','1','PETER');
Insert into XXX.TABLE1 (STATUS,PROJECT_NAME,VERSION_NUMBER,PERSON) values ('SUBMITTED','B','0','JOHN');
Created table should look like this:
TABLE1:
TABLE1.STATUS TABLE1.PROJECT_NAME TABLE1.VERSION_NUMBER TABLE1.PERSON
SUBMITTED A 0 PETER
SUBMITTED A 0 JOHN
SUBMITTED A 1 JOHN
NEW A 2 JOHN
SUBMITTED A 0 MARY
SUBMITTED B 0 PETER
NEW B 1 PETER
SUBMITTED B 0 JOHN
Result what I want get is this:
STATUS PROJECT_NAME VERSION_NUMBER PERSON STATUS_1 PROJECT_NAME_1 VERSION_NUMBER_1 PERSON_1
SUBMITTED A 0 PETER NEW B 1 PETER
SUBMITTED A 1 JOHN SUBMITTED B 0 JOHN
SUBMITTED A 0 MARY
Select which I am using now is:
select t.*,v.*
from TABLE1 t
left outer join ( select u.*
from TABLE1 u
where exists (select max(z.VERSION_NUMBER)
,z.PERSON
,z.PROJECT_NAME
from TABLE1 z
where z.PROJECT_NAME = 'B'
and u.PROJECT_NAME = z.PROJECT_NAME
and u.PERSON = z.PERSON
group by z.PERSON, z.PROJECT_NAME
having u.VERSION_NUMBER = max(z.VERSION_NUMBER))) v
on t.PERSON = v.PERSON
where exists (select max (w.VERSION_NUMBER)
,w.PERSON
,w.PROJECT_NAME
from TABLE1 w
where w.PROJECT_NAME = 'A'
and w.STATUS = 'SUBMITTED'
and t.PROJECT_NAME = w.PROJECT_NAME
and t.PERSON = w.PERSON
group by w.PERSON, w.PROJECT_NAME
having t.VERSION_NUMBER = max (w.VERSION_NUMBER))
QUESTION: What would be best(right) way to write such select (best practice), should I better use Analytic functions or use something else instead of EXISTS?
I think you've over-complicated this...
WITH
project_status (status, project_name, version_number, person)
AS
(SELECT 'SUBMITTED','A','0','PETER' FROM dual UNION ALL
SELECT 'SUBMITTED','A','0','JOHN' FROM dual UNION ALL
SELECT 'SUBMITTED','A','1','JOHN' FROM dual UNION ALL
SELECT 'NEW','A','2','JOHN' FROM dual UNION ALL
SELECT 'SUBMITTED','A','0','MARY' FROM dual UNION ALL
SELECT 'SUBMITTED','B','0','PETER' FROM dual UNION ALL
SELECT 'NEW','B','1','PETER' FROM dual UNION ALL
SELECT 'SUBMITTED','B','0','JOHN' FROM dual
)
SELECT DISTINCT
ps.person
,ps.project_name
,ps.status
FROM
project_status ps
WHERE 1=1
AND ps.project_name = 'A'
AND ps.status = 'SUBMITTED'
AND NOT EXISTS
(SELECT 1
FROM project_status ps2
WHERE ps2.person = ps.person
AND ps2.project_name = 'B'
)
;
purpose of select is to find out people who submitted project A and
have not done any activities in project B yet
If your purpose is just to get the people, then you don't need the complete rows. One method to answer this is to use group by and having:
select t1.person
from "XXX"."TABLE1" t1
group by t1.person
having sum(case when project_name = 'A' and status = 'New' then 1 else 0 end) > 0 and
sum(case when project_name = 'B' then 1 else 0 end) = 0;
If you need the complete rows, then Christian has a reasonable solution.
CREATE TABLE interview (uniqueID int identity(1,1),
date datetime,
recordtype int,
amount numeric(18, 4))
INSERT INTO interview values('6/30/13', 1, 27.95)
INSERT INTO interview values('5/20/13', 1, 21.85)
INSERT INTO interview values('5/22/13', 2, 27.90)
INSERT INTO interview values('12/11/12', 2, 23.95)
INSERT INTO interview values('6/13/13', 3, 24.90)
INSERT INTO interview values('6/30/13', 2, 27.95)
INSERT INTO interview values('5/20/13', 2, 21.85)
INSERT INTO interview values('5/22/13', 1, 27.90)
INSERT INTO interview values('12/11/12',1, 23.95)
INSERT INTO interview values('6/13/13', 3, 24.90)
INSERT INTO interview values('6/30/13', 3, 27.95)
INSERT INTO interview values('5/20/13', 3, 21.85)
INSERT INTO interview values('5/22/13', 2, 27.90)
INSERT INTO interview values('12/11/12', 1, 23.95)
INSERT INTO interview values('6/13/13', 1, 24.90)
How to get the following result? What would the query look like?
I was only able to get a partial to work, but my answer is not correct. I need to
somehow join the queries.
select distinct date, count(RecordType)as Count_unique1
from interview
where RecordType = '1'
group by date
select distinct date, count(RecordType)as Count_unique2
from interview
where RecordType = '2'
group by date
select distinct date, count(RecordType)as Count_unique3
from interview
where RecordType = '3'
group by date
select
date,
sum(case when RecordType = '1' then 1 else 0 end) as Count_unique1,
sum(case when RecordType = '2' then 1 else 0 end) as Count_unique2,
sum(case when RecordType = '3' then 1 else 0 end) as Count_unique3
from interview
group by date
Also in MSSQL you can use PIVOT
SELECT date, [1] AS Count_unique1,
[2] AS Count_unique2,
[3] AS Count_unique3
FROM (SELECT date,recordtype,amount FROM interview) p
PIVOT
(
COUNT (amount)
FOR recordtype IN ([1], [2], [3])
) AS pvt
ORDER BY pvt.date;
SQLFiddle demo
If RecordType is 1,2 and 3 in all cases this will be enough.
select date,
sum(RecordType = '1') as Count_unique1,
sum(RecordType = '2') as Count_unique2,
sum(RecordType = '3') as Count_unique3
from interview
group by date
hope you can help, this is driving me up the wall
I need to calculate the percentage of times a question has been failed, but this needs to be narrowed down by the geographical area, and product these questions are being asked against.
I have :
$CA002 = "( SELECT ROUND(100 * (SELECT count(CA002Result) from Data_Table where (CA002Result='Fail'))/count(CA002Result),2) from Data_Table) AS 'CA002 %'";
Which 'works' but just calculates against the whole set of records as an 'overall'
I'm trying :
$CA001 = "( SELECT ROUND(100 * (SELECT count(CA001Result) from Data_Table where (CA001Result='Fail' AND Area ='$Area'))/count(CA001Result) from Data_Table WHERE (Area='$Area'),2) AS 'CA001 %'";
And Also :
$CA001 = "( SELECT ROUND(100 * (SELECT count(CA001Result ) from Data_Table where (CA001Result='Fail' AND Product='$product' AND Area='$Area'))
/ count(CA001Result WHERE Product = '$product' AND Area='$Area'),2) from Data_Table) AS 'CA001 %'";
and am just getting errors no matter what I try, I just can't seem to work out what I need to put where.
Any great GREATLY apprteciated, thankyou.
Try this
//Filter by Area
create table t( id int, answer varchar(10),Area varchar(10));
insert into t select 1 , 'pass' , 'Area1';
insert into t select 2 , 'pass' , 'Area1';
insert into t select 3 , 'fail' , 'Area1';
insert into t select 4 , 'fail' , 'Area1';
insert into t select 5 , 'fail' , 'Area1';
insert into t select 6 , 'fail' , 'Area2';
SELECT
(x.TotalFailedAnswerRecord * 100) /y.TotalRecord AS Fail_percent
FROM
( SELECT Area,TotalFailedAnswerRecord = COUNT(answer)
FROM t
WHERE answer='fail' AND Area = 'Area1'
GROUP BY Area
)x
INNER JOIN
( SELECT Area,TotalRecord = COUNT(answer)
FROM t
WHERE Area = 'Area1'
GROUP BY Area
)y ON x.Area =y.Area
//Result
Fail_percent
-------------
60
//Filter by Area,Product
create table t( id int, answer varchar(10),Area varchar(10),Product varchar(10));
insert into t select 1 , 'pass' , 'Area1' ,'Product1';
insert into t select 2 , 'fail' , 'Area1' ,'Product1';
insert into t select 3 , 'fail' , 'Area1' ,'Product1';
insert into t select 4 , 'fail' , 'Area1' ,'Product1';
insert into t select 5 , 'fail' , 'Area1' ,'Product2';
insert into t select 6 , 'fail' , 'Area2' ,'Product2';
SELECT
(x.TotalFailedAnswerRecord * 100) /y.TotalRecord AS Fail_percent
FROM
( SELECT Area,Product,TotalFailedAnswerRecord = COUNT(answer)
FROM t
WHERE answer='fail' AND Area = 'Area1' AND Product = 'Product1'
GROUP BY Area,Product
)x
INNER JOIN
( SELECT Area,Product,TotalRecord = COUNT(answer)
FROM t
WHERE Area = 'Area1' AND Product = 'Product1'
GROUP BY Area,Product
)y ON x.Area =y.Area AND x.Product = y.Product
//Result
Fail_percent
-------------
75
Hope this helps
I have data in the following format in a table:
Acct# Amount
123 3.4
123T 4.5
124 2.3
124T 4.5
125 1.2
125T 2.4
How do I create a select statement where it totals up the account number as 123+123T and gives the following output:
123 7.9
124 6.8
125 3.6
You don't say any particular dialect of SQL
SELECT LEFT(Acct#,3), SUM(Amount)
FROM yourTable
GROUP BY LEFT(Acct#,3)
Or to handle arbitrary length account numbers
SELECT
CASE
WHEN Acct# LIKE '%T'
THEN SUBSTRING(Acct#,1,LEN(#Acct)-1)
ELSE Acct#
END,
SUM(Amount)
FROM yourTable
GROUP BY
CASE
WHEN Acct# LIKE '%T'
THEN SUBSTRING(Acct#,1,LEN(#Acct)-1)
ELSE Acct#
END
Or a more generic approach that will handle arbitrary mappings might be to construct a mapping table that you can then join on. There is quite a lot of missing information here as to the rules that need to be applied!
SELECT d.b, SUM(yt.Amount)
FROM yourTable yt
join (
SELECT '123' as a, '123' as b UNION ALL
SELECT '123T' as a, '123' as b UNION ALL
SELECT '124' as a, '124' as b UNION ALL
SELECT '124T' as a, '124' as b UNION ALL
SELECT '125' as a, '125' as b UNION ALL
SELECT '125T' as a, '125' as b
) d ON d.a = yt.Acct#
GROUP BY d.b
You can also try
SELECT REPLACE([Acct#],'T', ''), SUM(Amount)
FROM Acct
GROUP BY REPLACE([Acct#],'T', '')
Test Data
create table acct
([acct#] varchar(10),
amount decimal(10,2)
)
insert into acct([acct#], amount) values ('123', 3.4 )
insert into acct([acct#], amount) values ('123T', 4.5 )
insert into acct([acct#], amount) values ('124', 2.3)
insert into acct([acct#], amount) values ('124T', 4.5)
insert into acct([acct#], amount) values ('125', 1.2)
insert into acct([acct#], amount) values ('125T', 2.4)
I would have done that:
select b.acct#, (a.Amount + b.Amount) as Amount
FROM yourTable as a inner join yourTable as b
ON a.acct# = b.acct# + 'T'