Run a query consisting of subqueries only - sql

I have a SQL query that only consists of sub queries, But I cannot run it I get an SQL error, What is the correct Syntax to run query consisting of sub queries only...?
Query:
SELECT COUNT(id) AS 'totalNumOfCustomers'
FROM customers
WHERE customers.isDemo =0
AND customers.isLead=0
AND regTime < '2012-01-01'
SELECT COUNT(id) AS 'totalNumOfCustomersPerMonth'
FROM customers
WHERE customers.isDemo =0
AND customers.isLead=0
AND regTime >='2012-01-01'
AND regTime < '2012-02-01'
SELECT COUNT(positions.id) AS 'totalPositions',
ROUND(SUM(amount),2) - ROUND(SUM(payout),2) AS 'grossIncome'
FROM positions
LEFT JOIN customers ON positions.customerId = customers.id
WHERE date >= '2012-01-01'
AND date < '2012-02-01'
AND customers.isDemo=0
AND customers.isLead=0
AND status != 'canceled'
I am running this in WorkBench, The error message is this:
Error Code: 1064. You Have an error in your SQL syntax

How about this
select
(SELECT COUNT(id)
FROM customers
WHERE customers.isDemo =0
AND customers.isLead=0
AND regTime < '2012-01-01') as totalNumOfCustomers,
(SELECT COUNT(id)
FROM customers
WHERE customers.isDemo =0
AND customers.isLead=0
AND regTime >='2012-01-01'
AND regTime < '2012-02-01') as totalNumOfCustomersPerMonth,
(SELECT COUNT(positions.id)
FROM positions
LEFT JOIN customers ON positions.customerId = customers.id
WHERE date >= '2012-01-01'
AND date < '2012-02-01'
AND customers.isDemo=0
AND customers.isLead=0
AND status != 'canceled') as totalPositions,
(SELECT ROUND(SUM(amount),2) - ROUND(SUM(payout),2)
FROM positions
LEFT JOIN customers ON positions.customerId = customers.id
WHERE date >= '2012-01-01'
AND date < '2012-02-01'
AND customers.isDemo=0
AND customers.isLead=0
AND status != 'canceled') as grossIncome;

I think you get error, because there is no ; ant the end of each query. No error message, so just guessing

The two first queries you can easily express as one query:
SELECT COUNT(case when regTime < '2012-01-01' end ) AS totalNumOfCustomers
, COUNT(case when >='2012-01-01' AND regTime < '2012-02-01' end ) AS totalNumOfCustomersPerMonth
FROM customers
WHERE customers.isDemo =0
AND customers.isLead=0 ;
As others have suggested you can then use a cross join to take the third query into play

You can run these queries by putting them in the from clause and combining them using CROSS JOIN:
SELECT *
FROM (SELECT COUNT(id) totalNumOfCustomers
FROM customers
WHERE customers.isDemo =0
AND customers.isLead=0
AND regTime < '2012-01-01'
) t1 CROSS JOIN
(SELECT COUNT(id) as totalNumOfCustomersPerMonth
FROM customers
WHERE customers.isDemo =0
AND customers.isLead=0
AND regTime >='2012-01-01'
AND regTime < '2012-02-01'
) t2 CROSS JOIN
(SELECT COUNT(positions.id) AS totalPositions,
ROUND(SUM(amount),2) - ROUND(SUM(payout),2) AS grossIncome
FROM positions LEFT JOIN
customers
ON positions.customerId = customers.id
WHERE date >= '2012-01-01'
AND date < '2012-02-01'
AND customers.isDemo=0
AND customers.isLead=0
AND status <> 'canceled'
) t3;
Note: don't use single quotes for column and table aliases. That will lead to confusion. Single quotes should only be used for string and date constants.

Related

How to get the sum of values in a table interval?

The question is very simple :-). I'm a beginner.
tables
Declare #startDate date,
Declare #endDate date
Select
d.ID,
d.Date as DateDocumet,
dt.id As TypeDocument,
p.Name as ProductName,
p.Price as Price,
d.qty
from Documents d
LEFT join product p on d.ProductId = p.id
LEFT join DocumentType dt on d.DocumentTypeId = dt.id
Result:
A taskā€¦..
There are two date variables.
How to get the sum of values(qty) between dates(#startDate - #endDate).
How to get the sum of values(qty) up to #startDate.
How get the sum of values(qty) down to #endDate.
If DocumentType is 1. Then the value(qty) minus.
Looks like you need conditional aggregation SUM(CASE WHEN....
CROSS APPLY also makes it easier to pre-calculate the negative qty
Declare #startDate date;
Declare #endDate date;
Select
SUM(CASE WHEN d.Date < #startDate THEN QtyToSum END),
SUM(CASE WHEN d.Date >= #startDate AND d.Date < #endDate THEN QtyToSum END),
SUM(CASE WHEN d.Date >= #endDate THEN QtyToSum END),
from Documents d
CROSS APPLY (VALUES (CASE WHEN d.DocumentTypeId = 1 THEN -d.qty ELSE d.qty END) ) AS v(QtyToSum)

Needing Help Separating Data into columns

I'm currently using SQL at work to Query a database in order to display certain information. I have each item that's being pulled as separate entities. Whenever I run the Query my results only show under one column. Is there a way to separate this data into separate columns based on alias?
SELECT
count(o.orderid) AS Current_Daily
FROM
orders o
WHERE
o.ship_dt BETWEEN '2020-11-09 00:00:00' AND '2020-11-15 23:59:59'
AND o.orderstatus = 2
UNION
#UNION ALL
SELECT
count(o.orderid) AS Previous_Daily
FROM
orders o
WHERE
o.ship_dt BETWEEN '2019-11-09 00:00:00' AND '2019-11-15 23:59:59'
AND o.orderstatus = 2
UNION
#UNION ALL
SELECT
count(o.orderid) AS Current_Monthly
FROM
orders o
WHERE
o.ship_dt BETWEEN '2020-11-01 00:00:00' AND '2020-11-15 23:59:59'
AND o.orderstatus = 2
UNION
#UNION ALL
SELECT
count(o.orderid) AS Previous_Monthly
FROM
orders o
WHERE
o.ship_dt BETWEEN '2019-11-01 00:00:00' AND '2019-11-15 23:59:59'
AND o.orderstatus = 2
;
Any Help would be greatly appreciated.
Use conditional aggregation, as in:
select
sum(case when ship_dt >= '2020-11-09' and ship_dt < '2020-11-15' then 1 else 0 end) as current_daily,
sum(case when ship_dt >= '2020-11-01' and ship_dt < '2020-11-15' then 1 else 0 end) as current_monthly,
... -- more conditional "sum()"s if needed
from orders o
where orderstatus = 2
You probably just want conditional aggregation. Something like this:
SELECT SUM(CASE WHEN o.ship_dt >= '2020-11-09' AND o.ship_dt < '2020-11-16' THEN 1 ELSE 0 END) AS Current_Daily,
SUM(CASE WHEN o.ship_dt >= '2020-11-01' AND o.ship_dt < '2020-11-16' THEN 1 ELSE 0 END) AS Current_Monthly,
FROM orders o
WHERE o.orderstatus = 2;
You can add additional columns using similar logic.

How do I include records in a Summary query to include those that don't have data?

I have a query on a transaction table that returns the Summarized total on a column for each ID based on a data range. The query works great except it doesn't include those IDs that don't have data in the transaction table. How can I include those IDs in my result filled with a zero total. Here's a simplified version of my query.
SELECT tblID.IDName
,SUM(CASE
WHEN tblTransactions.idxTransType = 30
THEN CAST(tblTransactions.TimeAmount AS FLOAT) / 60.0
ELSE 0
END) AS 'Vacation'
FROM tblTransactions
INNER JOIN tblTransTypes ON tblTransactions.idxTransType = tblTransTypes.IdxTransType
INNER JOIN tblID ON tblTransactions.idxID = tblID.IdxID
WHERE (tblTransactions.Deleted = 0)
AND (tblTransactions.NotCurrent = 0)
AND (tblTransactions.TransDate >= CONVERT(DATETIME, 'March 1, 2018', 102))
AND (tblTransactions.TransDate <= CONVERT(DATETIME, 'April 11, 2018', 102))
GROUP BY tblID.IDName
Actually it's slightly more complicated than that:
SELECT
i.IDName,
SUM(CASE WHEN t.idxTransType = 30 THEN CAST(t.TimeAmount AS FLOAT) / 60.0 ELSE 0 END) AS 'Vacation'
FROM
tblID i
LEFT JOIN tblTransactions t ON t.idxID = i.IdxID AND t.Deleted = 0 AND t.NotCurrent = 0 AND t.TransDate BETWEEN '20180301' AND '20180411'
LEFT JOIN tblTransTypes tt ON tt.IdxTransType = t.idxTransType
GROUP BY
i.IDName;
You want left joins:
SELECT i.IDName,
SUM(CASE WHEN t.idxTransType = 30 THEN CAST(t.TimeAmount AS Float) / 60.0 ELSE 0 END) AS Vacation
FROM tblID i LEFT JOIN
tblTransactions t
ON t.idxID = i.IdxID AND
t.Deleted = 0 AND
t.NotCurrent = 0 AND
t.TransDate >= '2018-03-01' AND
t.TransDate <= '2018-04-11'
tblTransTypes tt
ON t.idxTransType = tt.IdxTransType
GROUP BY i.IDName;
Notes:
Table aliases make the query much easier to write and to read.
Use ISO/ANSI standard date formats.
The filter conditions on all but the first table belong in the ON clauses.

ORACLE SQL: Fill in missing dates

I have the following code which gives me production dates and production volumes for a thirty day period.
select
(case when trunc(so.revised_due_date) <= trunc(sysdate)
then trunc(sysdate) else trunc(so.revised_due_date) end) due_date,
(case
when (case when sp.pr_typ in ('VV','VD') then 'DVD' when sp.pr_typ in ('RD','CD')
then 'CD' end) = 'CD'
and (case when so.tec_criteria in ('PI','MC')
then 'XX' else so.tec_criteria end) = 'OF'
then sum(so.revised_qty_due)
end) CD_OF_VOLUME
from shop_order so
left join scm_prodtyp sp
on so.prodtyp = sp.prodtyp
where so.order_type = 'MD'
and so.plant = 'W'
and so.status_code between '4' and '8'
and trunc(so.revised_due_date) <= trunc(sysdate)+30
group by trunc(so.revised_due_date), so.tec_criteria, sp.pr_typ
order by trunc(so.revised_due_date)
The problem I have is where there is a date with no production planned, the date wont appear on the report. Is there a way of filling in the missing dates.
i.e. the current report shows the following ...
DUE_DATE CD_OF_VOLUME
14/04/2015 35,267.00
15/04/2015 71,744.00
16/04/2015 20,268.00
17/04/2015 35,156.00
18/04/2015 74,395.00
19/04/2015 3,636.00
21/04/2015 5,522.00
22/04/2015 15,502.00
04/05/2015 10,082.00
Note: missing dates (20/04/2015, 23/04/2015 to 03/05/2015)
Range is always for a thirty day period from sysdate.
How do you fill in the missing dates?
Do you need some kind of calendar table?
Thanks
You can get the 30-day period from SYSDATE as follows (I assume you want to include SYSDATE?):
WITH mydates AS (
SELECT TRUNC(SYSDATE) - 1 + LEVEL AS due_date FROM dual
CONNECT BY LEVEL <= 31
)
Then use the above to do a LEFT JOIN with your query (perhaps not a bad idea to put your query in a CTE as well):
WITH mydates AS (
SELECT TRUNC(SYSDATE) - 1 + LEVEL AS due_date FROM dual
CONNECT BY LEVEL <= 31
), myorders AS (
select
(case when trunc(so.revised_due_date) <= trunc(sysdate)
then trunc(sysdate) else trunc(so.revised_due_date) end) due_date,
(case
when (case when sp.pr_typ in ('VV','VD') then 'DVD' when sp.pr_typ in ('RD','CD')
then 'CD' end) = 'CD'
and (case when so.tec_criteria in ('PI','MC')
then 'XX' else so.tec_criteria end) = 'OF'
then sum(so.revised_qty_due)
end) CD_OF_VOLUME
from shop_order so
left join scm_prodtyp sp
on so.prodtyp = sp.prodtyp
where so.order_type = 'MD'
and so.plant = 'W'
and so.status_code between '4' and '8'
and trunc(so.revised_due_date) <= trunc(sysdate)+30
group by trunc(so.revised_due_date), so.tec_criteria, sp.pr_typ
order by trunc(so.revised_due_date)
)
SELECT mydates.due_date, myorders.cd_of_volume
FROM mydates LEFT JOIN myorders
ON mydates.due_date = myorders.due_date;
If you want to show a zero on "missing" dates instead of a NULL, use COALESCE(myorders.cd_of_volume, 0) AS cd_of_volume above.
what you can do is this :
creating a new table with all the days you need .
WITH DAYS AS
(SELECT TRUNC(SYSDATE) - ROWNUM DDD
FROM ALL_OBJECTS
WHERE ROWNUM < 365)
SELECT
DAYS.DDD
FROM
DAYS;
then full outer join between thoes table :
select DUE_DATE , CD_OF_VOLUME , DDD
from (
select
(case when trunc(so.revised_due_date) <= trunc(sysdate)
then trunc(sysdate) else trunc(so.revised_due_date) end) due_date,
(case
when (case when sp.pr_typ in ('VV','VD') then 'DVD' when sp.pr_typ in ('RD','CD')
then 'CD' end) = 'CD'
and (case when so.tec_criteria in ('PI','MC')
then 'XX' else so.tec_criteria end) = 'OF'
then sum(so.revised_qty_due)
end) CD_OF_VOLUME
from shop_order so
left join scm_prodtyp sp
on so.prodtyp = sp.prodtyp
where so.order_type = 'MD'
and so.plant = 'W'
and so.status_code between '4' and '8'
and trunc(so.revised_due_date) <= trunc(sysdate)+30
group by trunc(so.revised_due_date), so.tec_criteria, sp.pr_typ
order by trunc(so.revised_due_date)
) full outer join NEW_TABLE new on ( new .DDD = DUE_DATE )
where new .DDD between /* */ AND /* */ /* pick your own limit) */
you can get the gaps by using connect by and a left join:
assuming your schema is:
create table tbl(DUE_DATE date, CD_OF_VOLUME float);
insert into tbl values(to_date('14/04/2015','DD/MM/YYYY'),35267.00);
insert into tbl values(to_date('15/04/2015','DD/MM/YYYY'),71744.00);
insert into tbl values(to_date('16/04/2015','DD/MM/YYYY'),20268.00);
insert into tbl values(to_date('17/04/2015','DD/MM/YYYY'),35156.00);
insert into tbl values(to_date('18/04/2015','DD/MM/YYYY'),74395.00);
insert into tbl values(to_date('19/04/2015','DD/MM/YYYY'),3636.00);
insert into tbl values(to_date('21/04/2015','DD/MM/YYYY'),5522.00);
insert into tbl values(to_date('22/04/2015','DD/MM/YYYY'),15502.00);
insert into tbl values(to_date('04/05/2015','DD/MM/YYYY'),10082.00);
you can say:
with cte as
(
select (select min(DUE_DATE)-1 from tbl)+ level as dt
from dual
connect by level <= (select max(DUE_DATE)-min(DUE_DATE) from tbl)
)
select to_char(c.dt,'DD/MM/YYYY') gap,null volume
from cte c
left join tbl t on c.dt=t.DUE_DATE
where t.DUE_DATE is null
order by c.dt
Result:
GAP VOLUME
20/04/2015 (null)
23/04/2015 (null)
24/04/2015 (null)
25/04/2015 (null)
26/04/2015 (null)
27/04/2015 (null)
28/04/2015 (null)
29/04/2015 (null)
30/04/2015 (null)
01/05/2015 (null)
02/05/2015 (null)
03/05/2015 (null)
Notice: you can implement this in your original query, one simplest way is to wrap your query and use it as a subquery instead of tbl in above code snippet.

SQL Sum MTD & YTD

I have only just started looking into SQL.
I have a SQL Server 2008 r2 database that will return two fields DocDate & InvValue. I need to sum the InvValues as MTD & YTD as of Today's Date So it looks like
**Period** /////// **Total value**
MTD ////////////111111.11
YTD /////////////999999.99
I have done a fair amount of Googling and can do one or the other with SUM & DATEPART, but I am stuck with trying to do both.
Can someone give me some pseudo-code that would help me google a little further.
Thank you #Gordon Linoff, That helped a lot and I learned something, That I will find useful in the future.
My code now looks like:
SELECT
SUM(CASE WHEN YEAR(T1.[DocDate]) = YEAR(GETDATE()) THEN T0.[TotalSumSy] END) AS YTD,
SUM(CASE WHEN YEAR(T1.[DocDate]) = YEAR(GETDATE()) AND MONTH(T1.[DocDate]) = MONTH(GETDATE()) THEN T0.[TotalSumSy] END) AS MTD
FROM [dbo].[INV1] T0 INNER JOIN [dbo].[OINV] T1 ON T1.[DocEntry] = T0.[DocEntry]
However I now get
YTD.........MTD
99999.99....111111.11
And I need
YTD........99999.99
MTD........11111.11
Any further assistance would be appreciated.
You can do this with conditional aggregation:
select sum(case when year(docdate) = year(getdate()) then InvValue end) as YTD,
sum(case when year(docdate) = year(getdate()) and month(docdate) = month(getdaate())
then InvValue
end) as MTD
from table t;
This assumes you have no future dates in the table. If you do, add in docdate < getdate() to both clauses.
EDIT:
If you need this in two rows, you can simply do this:
select (case when n.n = 1 then 'YTD' else 'MTD' end) as which,
(case when n.n = 1 then YTD else MTD end) as value
from (select sum(case when year(docdate) = year(getdate()) then InvValue end) as YTD,
sum(case when year(docdate) = year(getdate()) and month(docdate) = month(getdaate())
then InvValue
end) as MTD
from table t
) cross join
(select 1 as n union all select 2) n;
SELECT
Period = 'MTD',
Total_value = SUM(T0.TotalSumSy)
FROM dbo.INV1 T0
INNER JOIN dbo.OINV T1
ON T1.DocEntry = T0.DocEntry
WHERE
T1.DocDate >= DATEADD(month,DATEDIFF(month,'20010101',GETDATE()),'20010101')
AND
T1.DocDate < DATEADD(month,1+DATEDIFF(month,'20010101',GETDATE()),'20010101')
UNION ALL
SELECT
'YTD',
SUM(T0.TotalSumSy)
FROM dbo.INV1 T0
INNER JOIN dbo.OINV T1
ON T1.DocEntry = T0.DocEntry
WHERE
T1.DocDate >= DATEADD(year,DATEDIFF(year,'20010101',GETDATE()),'20010101')
AND
T1.DocDate < DATEADD(year,1+DATEDIFF(year,'20010101',GETDATE()),'20010101') ;
The (complicated) conditions at the WHERE clauses are used instead of the YEAR(column) = YEAR(GETDATE() and the other you had previously, so indexes can be used. WHen you apply a function to a column, you make indexes unsuable (with some minor exceptions for some functions and some verios of SQL-Server.) So, the best thing is to try to convert the conditions to this type:
column <operator> AnyComplexFunction()