Sql Table Query - sql

I have following table with duplicate records.I want to retrieve record with duplicate id but different name,date.
CREATE TABLE Student1
(`id` int,`status` int,`amount` int , `Name` varchar(10), `date` varchar(55))
;
INSERT INTO Student1
(`id`,`status`,`amount`, `Name`, `date`)
VALUES
(1,0,4500, 'ram', '04/02/2012'),
(2,0,2000, 'shyam', '05/09/2013'),
(4,0,1500, 'ghanshyam', '08/11/2014'),
(3,0,4500, 'gopal', '04/02/2012'),
(2,0,8000, 'radheshyam', '15/11/2013'),
(4,1,1500, 'ghanshyam', '18/10/2015'),
(1,1,4500, 'ram', '14/02/2012'),
(2,0,6500, 'radhe', '11/11/2014'),
(3,1,4500, 'gopal', '14/02/2015')
;
Expected Result:
id status amount Name date
2 0 2000 shyam 05/09/2013
2 0 8000 radheshyam 15/11/2013
2 0 6500 radhe 11/11/2014

select * from Student1
where id in
(
select id from Student1
group by id
having count(distinct name) > 1
and count(distinct date) > 1
)

Related

How to group by two tables with CTE

I have three tables (Oracle):
sales_order
-------------
int so_key (pk)
int part_key (fk)
int condition_key (fk)
number unit_price
int qty_ordered
number unit_cost
date entry_date
quote
-------------
int q_key (pk)
int part_key (fk)
int condition_key (fk)
number unit_price
int qty_quoted
date entry_date
stock
-------------
int stock_key (pk)
int part_key (fk)
int condition (fk)
int qty_available
number unit_cost
And all three have foreign key references to these two tables:
part
-------------
int part_key (pk)
condition
-------------
int condition_key (pk)
I am writing a query that will aggregate the data into rows grouped by part and condition. However, I am unable to figure out how to group by BOTH part and condition. Here is the (functional) query that I have that groups by part only:
WITH
ctePart_Quotes AS
(
SELECT q.part_key
, COUNT(*) AS quotes_count
, SUM(q.unit_price * q.qty_quoted) AS quotes_amt_total
, SUM(q.qty_quoted) AS quotes_qty_total
FROM quote q
WHERE q.entry_date BETWEEN TO_DATE('01-Jan-2011', 'dd-mm-yyyy') AND TO_DATE('31-Dec-2011', 'dd-mm-yyyy')
GROUP BY q.part_key
)
, ctePart_Sales AS
(
SELECT so.part_key
, COUNT(*) AS sales_count
, SUM(so.unit_price * so.qty_ordered) AS sales_amt_total
, SUM(so.qty_ordered) AS sales_qty_total
, SUM(so.qty_ordered * so.unit_cost) AS cost_total
FROM sales_order so
WHERE so.entry_date BETWEEN TO_DATE('01-Jan-2011', 'dd-mm-yyyy') AND TO_DATE('31-Dec-2011', 'dd-mm-yyyy')
GROUP BY so.part_key
)
, ctePart_Stock AS
(
SELECT stm.part_key
, SUM(stm.qty_available) AS total_available
, SUM(stm.qty_available * stm.unit_cost) AS inv_cost
FROM stock stm
GROUP BY stm.part_key
)
SELECT p.part_key,
part_stock.total_available,
part_stock.inv_cost,
sales.sales_amt_total,
sales.sales_qty_total,
sales.sales_count,
sales.cost_total,
quotes.quotes_amt_total,
quotes.quotes_qty_total,
quotes.quotes_count
FROM parts p
LEFT OUTER JOIN ctePart_Quotes quotes
ON quotes.part_key = p.part_key
LEFT OUTER JOIN ctePart_Sales sales
ON sales.part_key = p.part_key
LEFT OUTER JOIN ctePart_Stock part_stock
ON part_stock.part_key = p.part_key
WHERE NOT(sales_amt_total IS NULL
AND sales_qty_total IS NULL
AND sales_count IS NULL
AND cost_total IS NULL
AND quotes_amt_total IS NULL
AND quotes_qty_total IS NULL
AND quotes_count IS NULL)
AND SALES_AMT_TOTAL > 10000
This query produces this output (totals grouped by part_key):
part_key | total_available | inv_cost | sales_amt_total | ...
---------|-----------------|----------|-----------------| ...
234 | 59 | 4923.90 | 29403.48 | ...
185 | 21 | 192.64 | 9034.95 | ...
102 | 102 | 8738.34 | 50382.20 | ...
...
But I'm trying to modify the query to produce this (totals grouped by part_key and condition_key):
part_key | condition_key | total_available | inv_cost | sales_amt_total | ...
---------|---------------|-----------------|----------|-----------------| ...
234 | 3 | 24 | 2360.50 | 16947.18 | ...
234 | 7 | 35 | 2563.40 | 12456.30 | ...
...
How do you do this?
EDIT: for clarification:
The complexity lies in: how do you join the condition in the final select? Because you are selecting FROM part but the condition relationship is through the other tables (sales_order, etc.). So you'd have to join through each of the tables (LEFT OUTER JOIN condition cond ON quotes.condition_key = cond.condition_key, etc.) but those joins would each be separate columns.
EDIT #2: someone provided a good image of the data model that illustrates the (proper, legitimate) relationship between part/condition but also the subtle complexity faced in this problem:
The main problem here seems to be your data model. Converting the table "descriptions" of your question into DDL code, and reversing this to a relational model (using Oracle Datamodeler), we find something like this:
DDL code
create table part ( part_key number primary key ) ;
create table condition ( condition_key number primary key ) ;
create table sales_order (
so_key number generated always as identity start with 3000 primary key
, part_key number references part
, condition_key number references condition
, unit_price number
, qty_ordered number
, unit_cost number
, entry_date date ) ;
create table quote (
q_key number generated always as identity start with 4000 primary key
, part_key number references part
, condition_key number references condition
, qty_quoted number
, unit_price number
, entry_date date );
create table stock (
stock_key number generated always as identity start with 5000 primary key
, part_key number references part
, condition_key number references condition
, qty_available number
, unit_cost number ) ;
Relational model (Oracle SQL Developer Data Modeler)
Looking at the model, it becomes clear that each PART can have several CONDITIONs. Thus, it may be necessary (for you) to decide, which condition you are referring to. That may not be easy. Suppose we have a part (with part_key) 1000. Now, we can record 3 different conditions, and use a specific condition for each of your 3 tables mentioned in your query.
-- one part, 3 conditions
begin
insert into part ( part_key ) values ( 1000 ) ;
insert into condition( condition_key ) values ( 2001 ) ;
insert into condition( condition_key ) values ( 2002 ) ;
insert into condition( condition_key ) values ( 2003 ) ;
insert into sales_order ( part_key, condition_key ) values ( 1000, 2001 ) ;
insert into quote ( part_key, condition_key ) values ( 1000, 2002 ) ;
insert into stock ( part_key, condition_key ) values ( 1000, 2003 ) ;
end ;
/
Which one of the 3 condition is supposed to be used for the query? Hard to tell.
-- not using WITH (subquery factoring) here - for clarity
select
P.part_key
, SO.condition_key
, Q.condition_key
, ST.condition_key
from part P
join sales_order SO on SO.part_key = P.part_key
join quote Q on Q.part_key = P.part_key
join stock ST on ST.part_key = P.part_key
;
-- output
PART_KEY CONDITION_KEY CONDITION_KEY CONDITION_KEY
1000 2001 2002 2003
Well - we could pick one of the conditions, couldn't we. However, even more conditions can exist for one and the same part ...
begin
insert into condition( condition_key ) values ( 2004 ) ;
insert into condition( condition_key ) values ( 2005 ) ;
insert into condition( condition_key ) values ( 2006 ) ;
insert into sales_order ( part_key, condition_key ) values ( 1000, 2004 ) ;
insert into quote ( part_key, condition_key ) values ( 1000, 2005 ) ;
insert into stock ( part_key, condition_key ) values ( 1000, 2006 ) ;
end ;
/
-- Same query as above now gives us:
PART_KEY CONDITION_KEY CONDITION_KEY CONDITION_KEY
1000 2001 2005 2006
1000 2001 2005 2003
1000 2001 2002 2006
1000 2001 2002 2003
1000 2004 2005 2006
1000 2004 2005 2003
1000 2004 2002 2006
1000 2004 2002 2003
Conclusion: Fix your data model. (We know this is sometimes easier said than done ...) Then, it will make sense to do some more work on your query.
__Update__
Now that we know that nothing can be done about the tables and the constraints, maybe the following queries will give you a starting point. We do not have proper test data, so let's just add some random values to the tables ...
-- PART and CONDITION -> 1000 integers each
begin
for i in 1 .. 1000
loop
insert into part ( part_key ) values ( i ) ;
insert into condition( condition_key ) values ( i ) ;
end loop;
end ;
/
Table QUOTE
-- 2 12s, 2 18s
SQL> select * from quote ;
Q_KEY PART_KEY CONDITION_KEY QTY_QUOTED UNIT_PRICE ENTRY_DATE
4000 10 100 55 500 01-MAY-11
4001 12 120 55 500 01-MAY-11
4002 12 37 56 501 01-MAY-11
4003 14 140 55 500 01-MAY-11
4004 15 46 56 501 01-MAY-11
4005 16 160 55 500 01-MAY-11
4006 18 180 55 500 01-MAY-11
4007 18 55 56 501 01-MAY-11
4008 20 200 55 500 01-MAY-11
Table SALES_ORDER
SQL> select * from sales_order ;
SO_KEY PART_KEY CONDITION_KEY UNIT_PRICE QTY_ORDERED UNIT_COST ENTRY_DATE
3000 10 100 500 55 400 05-MAY-11
3001 12 120 500 55 400 05-MAY-11
3002 14 140 500 55 400 05-MAY-11
3003 16 160 500 55 400 05-MAY-11
3004 18 180 500 55 400 05-MAY-11
3005 20 200 500 55 400 05-MAY-11
Table STOCK
SQL> select * from stock ;
STOCK_KEY PART_KEY CONDITION_KEY QTY_AVAILABLE UNIT_COST
5000 10 100 10 400
5001 12 120 10 400
5002 14 140 10 400
5003 14 100 12 402
5004 16 160 10 400
5005 18 180 10 400
5006 20 200 10 400
Assuming that only valid part/condition combinations are recorded, we can use FULL OUTER JOINs to get a first picture.
SQL> select
2 Q.part_key q_part , Q.condition_key q_cond
3 , SO.part_key so_part, SO.condition_key so_cond
4 , ST.part_key st_part, ST.condition_key st_cond
5 from quote Q
6 full join sales_order SO
7 on SO.part_key = Q.part_key and SO.condition_key = Q.condition_key
8 full join stock ST
9 on ST.part_key = SO.part_key and ST.condition_key = SO.condition_key
10 ;
-- result
Q_PART Q_COND SO_PART SO_COND ST_PART ST_COND
10 100 10 100 10 100
12 120 12 120 12 120
12 37 NULL NULL NULL NULL
14 140 14 140 14 140
15 46 NULL NULL NULL NULL
16 160 16 160 16 160
18 180 18 180 18 180
18 55 NULL NULL NULL NULL
20 200 20 200 20 200
NULL NULL NULL NULL 14 100
Then, we can use Analytic Functions for the various calculations. Note that we do not use GROUP BY here, the grouping is done via ... partition by Q.part_key, Q.condition_key ... (More about analytic functions: Oracle documentation, and examples here).
-- Skeleton query ...
-- Note that you will have need to write over(...) several times.
-- Add a WHERE clause and conditions as required.
select
Q.part_key as q_part, Q.condition_key as q_cond,
count( Q.part_key ) over ( partition by Q.part_key, Q.condition_key ) as q_count
--
-- Q example sums
-- , sum( Q.unit_price * Q.qty_quoted )
-- over ( partition by Q.part_key, Q.condition_key ) as qat -- quotes_amt_total
-- , sum( Q.qty_quoted )
-- over ( partition by Q.part_key, Q.condition_key ) as qqt -- quotes_qty_total
--
, SO.part_key as so_part, SO.condition_key as so_cond
, count( SO.part_key ) over ( partition by SO.part_key, SO.condition_key ) as so_count
--
-- SO sums here
--
, ST.part_key as st_part, ST.condition_key as st_cond
, count( ST.part_key ) over ( partition by ST.part_key, ST.condition_key ) as st_count
from sales_order SO
full join quote Q
on SO.part_key = Q.part_key and SO.condition_key = Q.condition_key
full join stock ST
on ST.part_key = SO.part_key and ST.condition_key = SO.condition_key
-- where ...
;
Result
-- output
Q_PART Q_COND Q_COUNT SO_PART SO_COND SO_COUNT ST_PART ST_COND ST_COUNT
10 100 1 10 100 1 10 100 1
12 37 1 NULL NULL 0 NULL NULL 0
12 120 1 12 120 1 12 120 1
14 140 1 14 140 1 14 140 1
15 46 1 NULL NULL 0 NULL NULL 0
16 160 1 16 160 1 16 160 1
18 55 1 NULL NULL 0 NULL NULL 0
18 180 1 18 180 1 18 180 1
20 200 1 20 200 1 20 200 1
NULL NULL 0 NULL NULL 0 14 100 1
The trick is to first create a Carthesian product (The condition table only has ~30 rows), and maybe suppress the unwanted result rows later:
This may look sub-optimal, but it will avoid a join onCOALESCE()d keyfields, which could perform badly.
WITH
ctePart_Quotes AS
(
SELECT q.part_key, q.condition_key
, COUNT(*) AS quotes_count
, SUM(q.unit_price * q.qty_quoted) AS quotes_amt_total
, SUM(q.qty_quoted) AS quotes_qty_total
FROM quote q
WHERE q.entry_date BETWEEN TO_DATE('01-Jan-2011', 'dd-mm-yyyy') AND TO_DATE('31-Dec-2011', 'dd-mm-yyyy')
GROUP BY q.part_key, q.condition_key
)
, ctePart_Sales AS
(
SELECT so.part_key, so.condition_key
, COUNT(*) AS sales_count
, SUM(so.unit_price * so.qty_ordered) AS sales_amt_total
, SUM(so.qty_ordered) AS sales_qty_total
, SUM(so.qty_ordered * so.unit_cost) AS cost_total
FROM sales_order so
WHERE so.entry_date BETWEEN TO_DATE('01-Jan-2011', 'dd-mm-yyyy') AND TO_DATE('31-Dec-2011', 'dd-mm-yyyy')
GROUP BY so.part_key, so.condition_key
)
, ctePart_Stock AS
(
SELECT stm.part_key, stm.condition_key
, SUM(stm.qty_available) AS total_available
, SUM(stm.qty_available * stm.unit_cost) AS inv_cost
FROM stock stm
GROUP BY stm.part_key, stm.condition_key
)
SELECT p.part_key,
c.condition_key,
part_stock.total_available,
part_stock.inv_cost,
sales.sales_amt_total,
sales.sales_qty_total,
sales.sales_count,
sales.cost_total,
quotes.quotes_amt_total,
quotes.quotes_qty_total,
quotes.quotes_count
FROM parts p
CROSS JOIN condition c -- <<-- Here
LEFT OUTER JOIN ctePart_Quotes quotes
ON quotes.part_key = p.part_key
AND quotes.condition_key = c.condition_key -- <<-- Here
LEFT OUTER JOIN ctePart_Sales sales
ON sales.part_key = p.part_key
AND sales.condition_key = c.condition_key -- <<-- Here
LEFT OUTER JOIN ctePart_Stock part_stock
ON part_stock.part_key = p.part_key
AND part_stock.condition_key = c.condition_key -- <<-- Here
WHERE NOT(sales_amt_total IS NULL
AND sales_qty_total IS NULL
AND sales_count IS NULL
AND cost_total IS NULL
AND quotes_amt_total IS NULL
AND quotes_qty_total IS NULL
AND quotes_count IS NULL) -- <<-- And maybe Here, too
AND SALES_AMT_TOTAL > 10000
;
Maybe this works for you:
WITH
ctePart_Quotes AS
(
SELECT q.part_key,
q.condition_key
, COUNT(*) AS quotes_count
, SUM(q.unit_price * q.qty_quoted) AS quotes_amt_total
, SUM(q.qty_quoted) AS quotes_qty_total
FROM quote q
WHERE q.entry_date BETWEEN TO_DATE('01-Jan-2011', 'dd-mm-yyyy') AND TO_DATE('31-Dec-2011', 'dd-mm-yyyy')
GROUP BY q.part_key,
q.condition_key
)
, ctePart_Sales AS
(
SELECT so.part_key,
so.condition_key
, COUNT(*) AS sales_count
, SUM(so.unit_price * so.qty_ordered) AS sales_amt_total
, SUM(so.qty_ordered) AS sales_qty_total
, SUM(so.qty_ordered * so.unit_cost) AS cost_total
FROM sales_order so
WHERE so.entry_date BETWEEN TO_DATE('01-Jan-2011', 'dd-mm-yyyy') AND TO_DATE('31-Dec-2011', 'dd-mm-yyyy')
GROUP BY so.part_key,
so.condition_key
)
, ctePart_Stock AS
(
SELECT stm.part_key,
stm.condition_key
, SUM(stm.qty_available) AS total_available
, SUM(stm.qty_available * stm.unit_cost) AS inv_cost
FROM stock stm
GROUP BY stm.part_key,
stm.condition_key
)
SELECT p.part_key,
cte.condition_key,
cte.total_available,
cte.inv_cost,
cte.sales_amt_total,
cte.sales_qty_total,
cte.sales_count,
cte.cost_total,
cte.quotes_amt_total,
cte.quotes_qty_total,
cte.quotes_count
FROM parts p
LEFT OUTER JOIN (SELECT coalesce(quotes.part_key, sales.part_key, part_stock.part_key) part_key,
coalesce(quotes.condition_key, sales.condition_key, part_stock.condition_key) condition_key,
quotes.quotes_count,
quotes.quotes_amt_total,
quotes.quotes_qty_total,
sales.sales_count,
sales.sales_amt_total,
sales.sales_qty_total,
sales.cost_total,
part_stock.total_available,
part_stock.inv_cost
FROM ctePart_Quotes quotes
FULL JOIN ctePart_Sales sales
ON sales.part_key = quotes.part_key
AND sales.condition_key = quotes.condition_key
FULL JOIN ctePart_Stock part_stock
ON part_stock.part_key = sales.part_key
AND part_stock.condition_key = sales.condition_key) cte
ON cte.part_key = p.part_key
WHERE NOT(sales_amt_total IS NULL
AND cte.sales_qty_total IS NULL
AND cte.sales_count IS NULL
AND cte.cost_total IS NULL
AND cte.quotes_amt_total IS NULL
AND cte.quotes_qty_total IS NULL
AND cte.quotes_count IS NULL)
AND SALES_AMT_TOTAL > 10000;
It also groups by condition_key in the CTEs. Then it FULL JOINs the CTEs together using coalesce to compensate for null values of part_key or condition_key in the first tables (But maybe there is none, if every combination of part_keyand condition_key, that is present in one of the tables is also present in the respective two other tables.). The result is then LEFT JOINed to part using part_key.

Display results of multiple count in a sql query

There are two table:
Table persons:
P_id Name BirthDate
1 N1 2016-08-02
2 N2 2015-05-02
3 N3 2013-06-01
4 N4 2014-01-09
Table visited:(p_id is foreign key to table persons)
Id. Visitor_id. P_id. Visit_date
1 10 1 2017-03-05
2 11 2 2017-01-01
3 10 2 2017-02-03
4 12 3 2016-05-07
5 11 4 2016-04-09
6 10 1 2017-04-09
We are going to get the count of visited persons who their old are under 1, between 1 and 2, between 2 and 3 at date of visit_date by each visitor_id.
The results like :
Visitor_id Under_one Bet_one_two Bet_two_three
10 2 1 0
11 0 1 1
12 0 0 1
Could anyone help me how write a query in sql server for getting the results?
In above results, 0,1,2 means that we subtract of two date(visited_date - birthdate), for example : the result of 2013/03/05 - 2011/06/07 is between 1 and 2
you can try a pivot query like below
select
visitor_id,
Under_one=ISNULL([0],0),
Bet_one_two=ISNULL([1],0),
Bet_two_three=ISNULL([2],0)
from
(
select visitor_id, datediff(m,BirthDate,visit_date)/12 age_in_years,count(1) count from persons p join
visited v on p.p_id=v.p_id
group by visitor_id,datediff(m,BirthDate,visit_date)/12
) src
pivot
(
max(count) for age_in_years in ([0],[1],[2])
)p
see live demo
/*
DROP TABLE Visited
DROP TABLE Persons
DROP TABLE #Data
DROP TABLE #Results
*/
CREATE TABLE Persons
(
[P_id.] INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
[Name] NVARCHAR(2),
BirthDate DATETIME
)
INSERT INTO PERSONS ([Name],BirthDate) VALUES ('N1','2016-08-02')
INSERT INTO PERSONS ([Name],BirthDate) VALUES ('N2','2015-05-02')
INSERT INTO PERSONS ([Name],BirthDate) VALUES ('N3','2013-06-01')
INSERT INTO PERSONS ([Name],BirthDate) VALUES ('N4','2014-01-09')
GO
CREATE TABLE Visited
(
[ID.] INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
[Visitor_id.] INT,
[P_id.] INT REFERENCES Persons,
Visit_date DATETIME
)
GO
INSERT INTO Visited ([Visitor_id.],[P_id.],Visit_date) VALUES (10,1,'2017-03-05')
INSERT INTO Visited ([Visitor_id.],[P_id.],Visit_date) VALUES (11,2,'2017-01-01')
INSERT INTO Visited ([Visitor_id.],[P_id.],Visit_date) VALUES (10,2,'2017-02-03')
INSERT INTO Visited ([Visitor_id.],[P_id.],Visit_date) VALUES (12,3,'2016-05-07')
INSERT INTO Visited ([Visitor_id.],[P_id.],Visit_date) VALUES (11,4,'2016-04-09')
INSERT INTO Visited ([Visitor_id.],[P_id.],Visit_date) VALUES (10,1,'2017-04-09')
GO
SELECT [Visitor_id.],
CASE WHEN DATEPART(YY,v.visit_date-p.birthdate) = 1900 THEN 'Under_one'
WHEN DATEPART(YY,v.visit_date-p.birthdate) = 1901 THEN 'Bet_one_two'
WHEN DATEPART(YY,v.visit_date-p.birthdate) = 1902 THEN 'Bet_two_three'
END AS Age,
COUNT([Visitor_id.]) AS Number
INTO #Data
FROM Persons p INNER JOIN Visited v on p.[P_id.]=v.[P_id.]
GROUP BY [Visitor_id.],DATEPART(YY,v.visit_date-p.birthdate)
GO
CREATE TABLE #Results
(
Visitor_ID INT,
Under_one INT,
Bet_one_two INT,
Bet_two_three INT
)
GO
DECLARE #Visitor_id INT = (SELECT MIN([Visitor_id.]) FROM #Data)
WHILE #Visitor_id <= (SELECT MAX([Visitor_id.]) FROM #Data)
BEGIN
INSERT INTO #Results VALUES
(
(SELECT #Visitor_id)
,
(SELECT Number FROM #Data WHERE [Visitor_id.]=#Visitor_id AND Age = 'Under_one')
,
(SELECT Number FROM #Data WHERE [Visitor_id.]=#Visitor_id AND Age = 'Bet_one_two')
,
(SELECT Number FROM #Data WHERE [Visitor_id.]=#Visitor_id AND Age = 'Bet_two_three')
)
SET #Visitor_id = #Visitor_id + 1
END
UPDATE #Results SET Under_one = 0 WHERE Under_one IS NULL
GO
UPDATE #Results SET Bet_one_two = 0 WHERE Bet_one_two IS NULL
GO
UPDATE #Results SET Bet_two_three = 0 WHERE Bet_two_three IS NULL
GO
SELECT * FROM #Results
How about something like:
CREATE TABLE persons
(p_id int, name varchar(5), birthday date);
INSERT INTO persons
(p_id, name, birthday)
VALUES
(1, 'N1', '2016-08-02'),
(2, 'N2', '2015-05-02'),
(3, 'N3', '2013-06-01'),
(4, 'N4', '2014-01-09');
CREATE TABLE visited
(id int, visitor_id int,p_id int, visit_date date)
;
INSERT INTO visited(id, visitor_id,p_id, visit_date)
VALUES
(1,10,1,'2017-03-05'),
(2,11,2,'2017-01-01'),
(3,10,2,'2017-02-03'),
(4,12,3,'2016-05-07'),
(5,11,4,'2016-04-09'),
(6,10,1,'2017-04-09');
WITH visitAge(visitor_ID, VisitAge) AS
(SELECT
v.visitor_ID, DateDiff(Year, birthday,visit_date) as VisitAge
FROM visited v
INNER JOIN persons p on v.p_ID = p.p_ID
)
SELECT
visitor_ID,
SUM(CASE WHEN VisitAge < 1 THEN 1 ELSE 0 END ) AS under_one,
SUM(CASE WHEN VisitAge >= 1 AND VisitAge < 2 THEN 1 ELSE 0 END ) AS Bet_one_two,
SUM(CASE WHEN VisitAge >= 2 AND VisitAge < 3 THEN 1 ELSE 0 END ) AS Bet_two_three
FROM
visitAge
GROUP BY visitor_ID;
not durable solution...but for what I see in the question...it's a start for you....
SQL Fiddle link

Table Multiple Sql Query Union

I have following table which is having duplicate record with respect to different fields:
CREATE TABLE Student1
(`id` int,`status` int,`amount` int , `Name` varchar(10), `date` varchar(55))
;
INSERT INTO Student1
(`id`,`status`,`amount`, `Name`, `date`)
VALUES
(1,0,4500, 'ram', '04/02/2012'),
(2,0,2000, 'shyam', '05/09/2013'),
(4,0,1500, 'ghanshyam', '08/11/2014'),
(3,0,4500, 'gopal', '04/02/2012'),
(2,0,8000, 'radheshyam', '15/11/2013'),
(4,1,1500, 'ghanshyam', '18/10/2015'),
(1,1,4500, 'ram', '14/02/2012'),
(2,0,6500, 'radhe', '11/11/2014'),
(3,1,4500, 'gopal', '14/02/2015'),
(5,1,4500, 'gopala', '04/02/2015'),
(5,1,4500, 'gopala', '04/02/2015'),
(6,0,14500, 'gopal', '14/02/2015')
;
I have 3 conditions to filter the table:
No complete duplicate record
If record with same id but different Name and date field then add all of them to final result
If status=1 for any record then select that record of respective id
Add all record with id different from id of above 3 conditions
I have written this query:
SELECT * FROM Student1
GROUP BY id,status,amount,Name,date
HAVING COUNT(*) > 1
UNION
SELECT * FROM Student1 Student1
WHERE id IN
(
SELECT id FROM Student1
GROUP BY id
HAVING COUNT(DISTINCT name) > 1
AND COUNT(DISTINCT date) > 1
)
UNION
SELECT * FROM Student1 Student1
WHERE status=1 AND id IN
(
SELECT id FROM Student1
GROUP BY id
HAVING COUNT(id) >= 2
);
Result:
id status amount Name date
4 1 1500 ghanshyam 18/10/2015
1 1 4500 ram 14/02/2012
3 1 4500 gopal 14/02/2015
5 1 4500 gopala 04/02/2015
2 0 2000 shyam 05/09/2013
2 0 8000 radheshyam 15/11/2013
2 0 6500 radhe 11/11/2014
As you can see 1st Select avoid duplicate, 2nd Select record with same id having different Name, date, 3rd Select to get record with id=1. I am using UNION to avoid duplication in result.
Now I need to add 4th query to get the record id=6 which is not present in all the above condition.
Expected Result:
id status amount Name date
4 1 1500 ghanshyam 18/10/2015
1 1 4500 ram 14/02/2012
3 1 4500 gopal 14/02/2015
5 1 4500 gopala 04/02/2015
2 0 2000 shyam 05/09/2013
2 0 8000 radheshyam 15/11/2013
2 0 6500 radhe 11/11/2014
6 0 14500 gopal 14/02/2015
I need to solve the 4th query. Please help.
If the only condition you want to filter, is id = 6, it is enough to add just:
SELECT * FROM Student1 WHERE id=6;
Which is direct translation of your request into SQL. And full version will be:
SELECT * FROM Student1
GROUP BY id,status,amount,Name,date
HAVING COUNT(*) > 1
UNION
SELECT * FROM Student1 Student1
WHERE id IN
(
SELECT id FROM Student1
GROUP BY id
HAVING COUNT(DISTINCT name) > 1
AND COUNT(DISTINCT date) > 1
)
UNION
SELECT * FROM Student1 Student1
WHERE status=1 AND id IN
(
SELECT id FROM Student1
GROUP BY id
HAVING COUNT(id) >= 2
)
UNION
SELECT * FROM Student1 WHERE id=6;
Result is as requested but in different order. DEMO
However, if you would like to get all id which were not filtered with your coditions, but you don't know their values, I would use a VIEW:
CREATE VIEW Student2 AS
SELECT * FROM Student1
GROUP BY id,status,amount,Name,date
HAVING COUNT(*) > 1
UNION
SELECT * FROM Student1 Student1
WHERE id IN
(
SELECT id FROM Student1
GROUP BY id
HAVING COUNT(DISTINCT name) > 1
AND COUNT(DISTINCT date) > 1
)
UNION
SELECT * FROM Student1 Student1
WHERE status=1 AND id IN
(
SELECT id FROM Student1
GROUP BY id
HAVING COUNT(id) >= 2
);
And then query with it:
SELECT * FROM Student2
UNION
SELECT * FROM Student1 WHERE id NOT IN (SELECT id FROM Student2);
The result is the same. DEMO

Retrieve matching rows using join

This is a simplified version of my problem.
I have table like below
Id Name SNumber
100 XYZ 123
100 XYZ 123
101 ABC 123
103 QAZ 123
100 XYZ 971
100 XYZ 872
100 XYZ 659
102 PQR 145
102 PQR 707
103 QAZ 421
I want to count rows having Snumber as '123' ie Total column and rows having Snumber not as '123' i.e. otherTotal column
Id Name Total OtherTotal
100 XYZ 2 3
101 ABC 1 0
102 PQR 0 2
103 QAZ 1 1
What I am doing is using join
Select xx.*,otherTotal
From
( Select Id,Name,count(*) as Total
From table
Where Snumber like '123'
Group By id,name
)xx
Inner join
( Select Id,Name,count(*) as otherTotal
From table
Where Snumber not like '123'
Group By id,name
)yy
On xx.Id=yy.Id
But this will only return rows if particular Id has both Snumber as 123 and not as 123
Data returned is like below
Id Name Total OtherTotal
100 XYZ 2 3
103 QAZ 1 1
Now there is no guarntee that a particular Id will always have Snumber as 123 so I can't use Left or Right join. How to solve this quagmire ? Giggity
Try this:
SELECT id, name,
COUNT(CASE WHEN SNumber = 123 THEN 1 END) Total,
COUNT(CASE WHEN SNumber <> 123 THEN 1 END) OtherTotal
FROM t
GROUP BY id, name
ORDER BY id
Fiddle here.
select
Id, Name,
sum(case when SNumber = 123 then 1 else 0 end) as Total,
sum(case when SNumber <> 123 then 1 else 0 end) as OtherTotal
from Table1
group by Id, Name
order by Id
or
select
Id, Name,
count(*) - count(nullif(SNumber, 123)) as Total,
count(nullif(SNumber, 123)) as OtherTotal
from Table1
group by Id, Name
order by Id
sql fiddle demo
try this one.
DECLARE #TABLE TABLE (ID INT, NAME VARCHAR(40), SNUMBER INT)
INSERT INTO #TABLE
VALUES
(100 ,'XYZ', 123),
(100 ,'XYZ', 123),
(101 ,'ABC', 123),
(103 ,'QAZ', 123),
(100 ,'XYZ', 971),
(100 ,'XYZ', 872),
(100 ,'XYZ', 659),
(102 ,'PQR', 145),
(102 ,'PQR', 707),
(103 ,'QAZ', 421)
SELECT
ID,
NAME,
(
SELECT
COUNT(SNUMBER) FROM #TABLE B
WHERE
SNUMBER = '123' AND A.ID = B.ID
) AS TOTAL,
(
SELECT
COUNT(SNUMBER) FROM #TABLE B
WHERE
SNUMBER <> '123' AND A.ID = B.ID
) AS OTHERTOTAL
FROM
#TABLE A
GROUP BY ID, NAME

update of a column based on max date and group by

i have three tables orders, orders_delivered, orders_delivered_sta
and the data in the three tables look like
table orders
orders_id
10
11
12
13
table orders_delivered
orders_delivered_id orders_id
10 1000
10 1001
11 1002
12 1003
12 1004
13 1005
13 1006
13 1007
table orders_delivered_sta
orders_delivered_sta_id orders_delivered_id date now_ind
1 1000 02/11/2011 0
2 1000 01/10/2006 0
3 1000 09/13/2011 0
4 1001 01/19/2010 0
5 1001 02/21/2011 0
6 1002 02/11/2009 0
7 1002 08/27/2010 0
8 1003 07/15/2012 0
9 1004 03/09/2007 0
10 1010 10/01/2010 0
11 1011 03/27/2011 0
12 1012 07/25/2010 0
13 1013 09/18/2004 0
so i need to update orders_delivered_sta table such that now_ind should be 1 for the max date of one orders_delivered_id
like for one orders_delivered_id 1000 the max date is 09/13/2011 for this set of orders_delivered_id and date (1000,09/13/2011) the now_ind should be 1 and if the column orders_delivered_id has one and only one id then that should be changed to 1
there is some data in orders_delivered_sta table which are not in orders and orders_delivered tables those need not to be changed. the orders_delivered_id which are in oreders_delivered table only needs to change
so the desired output should look like
table orders_delivered_sta
orders_delivered_sta_id orders_delivered_id date now_ind
1 1000 02/11/2011 0
2 1000 01/10/2006 0
3 1000 09/13/2011 1
4 1001 01/19/2010 0
5 1001 02/21/2011 1
6 1002 02/11/2009 0
7 1002 08/27/2010 1
8 1003 07/15/2012 1
9 1004 03/09/2007 1
10 1010 10/01/2010 0
11 1011 03/27/2011 0
12 1012 07/25/2010 0
13 1013 09/18/2004 0
table structure:
create table orders
(
order_id int primary key
)
insert into orders select 10
insert into orders select 11
insert into orders select 12
insert into orders select 13
create table orders_delivered
(
orders_delivered_id int primary key,
orders_id int FOREIGN KEY(orders_id)REFERENCES orders (orders_id)
)
insert into orders_delivered select 1000,10
insert into orders_delivered select 1001,10
insert into orders_delivered select 1002,11
insert into orders_delivered select 1003,12
insert into orders_delivered select 1004,12
insert into orders_delivered select 1005,13
insert into orders_delivered select 1006,13
insert into orders_delivered select 1007,13
create table orders_delivered_sta
(
orders_delivered_sta_id int primary key,
orders_delivered_id int FOREIGN KEY(orders_delivered_id)REFERENCES orders_delivered (orders_delivered_id),
date char(10),
now_ind int
)
insert into orders_delivered_sta select 1,1000,'02/11/2011', 0
insert into orders_delivered_sta select 2,1000,'01/10/2006', 0
insert into orders_delivered_sta select 3,1000,'09/13/2011', 0
insert into orders_delivered_sta select 4,1001,'01/19/2010', 0
insert into orders_delivered_sta select 5,1001,'02/21/2011', 0
insert into orders_delivered_sta select 6,1002,'02/11/2009', 0
insert into orders_delivered_sta select 7,1002,'08/27/2010', 0
insert into orders_delivered_sta select 8,1003,'07/15/2012', 0
insert into orders_delivered_sta select 9,1004,'03/09/2007', 0
insert into orders_delivered_sta select 10,1010,'10/01/2010', 0
insert into orders_delivered_sta select 11,1011,'03/27/2011', 0
insert into orders_delivered_sta select 12,1012,'07/25/2010', 0
insert into orders_delivered_sta select 13,1013,'09/18/2004', 0
You could use a CTE and a window MAX():
;
WITH max_dates AS (
SELECT
*,
max_date = MAX(date) OVER (PARTITION BY orders_delivered_id)
FROM orders_delivered_sta
WHERE orders_delivered_id IN (SELECT orders_delivered_id FROM orders_delivered)
)
UPDATE max_dates
SET now_ind = 1
WHERE date = max_date
References:
WITH common_table_expression (Transact-SQL)
OVER Clause (Transact-SQL)
This is the query in MySQL, but translating it to SQL-Server should be straight forward as I am using plain SQL. Notice I have changed the date to be in a different form (YYYY-MM-DD) to avoid castings from string to date.
update t3
set t3.now_ind = 1
where t3.orders_delivered_sta_id in (
select distinct t1.orders_delivered_sta_id from t1
left join (
select t2.orders_delivered_id, max(t2.adate) as MaxDate from t2
group by t2.orders_delivered_id
) t2 on (t1.orders_delivered_id = t2.orders_delivered_id) and (t1.adate = t2.MaxDate)
where t2.orders_delivered_id is not null
) and exists (
select * from o1
join od1 on (o1.order_id = od1.orders_delivered_id)
where (t3.orders_delivered_id = od1.orders_id)
)
Here is an example
Hope this helps
PS: You did need those 3 tables... I'll read questions better next time :)
Try this:
UPDATE orders_delivered_sta
SET now_ind = 1
WHERE orders_delivered_sta_id IN(
SELECT orders_delivered_sta_id
FROM (
SELECT orders_delivered_sta_id,
ROW_NUMBER() OVER(PARTITION BY orders_delivered_id ORDER BY date DESC) AS num
FROM orders_delivered_sta) AS T
WHERE T.num = 1)