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
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)
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.
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.
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.
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()