Subtract two values from the same column - sql

I want to subtract two values from the same column like this:
SELECT tblTask.CustomerName,
Sum(Isnull(Cast(Value AS FLOAT), 0)) AS summa
FROM tblExtraFieldData
INNER JOIN tblTask
ON tblExtraFieldData.OwnerId = tblTask.Id
INNER JOIN tblLog
ON tblExtraFieldData.OwnerId = tblLog.OwnerId
WHERE tblLog.Modified BETWEEN '2016-11-25' AND '2016-12-31'
AND tblExtraFieldData.FieldId = '10052'
AND tblTask.Status = '5'
AND tblLog.Text LIKE '%Exporterat%'
AND tblTask.ProjectNr NOT LIKE 'Fastpris'
GROUP BY tblTask.CustomerName
ORDER BY summa
And now I want to subtract this with a value that is found in tblExtraFieldData.Value and the FieldId = '10048' in the table tblExtraFieldData

Related

SQL - Dates equal from two columns

I have this query and would like to see the dates only where effective_date from one table = renewal_date from the other table.
SELECT
facets_re_group.prospect_nbr, rmr_run_status, insert_date, renewal_date,
package_item_cd, quote_type, effective_date, quote_expiration_ind,
mhs_lob_code
FROM
facets_re_group
INNER JOIN
facets_re_cur_package ON facets_re_cur_package.prospect_nbr = facets_re_group.prospect_nbr
JOIN
qo_quote ON qo_quote.prospect_nbr = facets_re_group.prospect_nbr
WHERE
insert_date >= to_date('01/01/2020','mm/dd/yyyy')
AND package_item_cd = 'HRA'
AND quote_expiration_ind IS NULL
AND mhs_lob_code NOT IN 'DTL1'
AND mhs_lob_code NOT IN 'DTL2'
AND mhs_lob_code NOT IN 'VIS1'

Why is SQL doing an inner join where an outer join is needed

I have two tables which I want to "outer" join (and then fetch) using SQL. The exact SQL query (in question) is:
SELECT
LEFT(a.cusip, 6) AS cusip6,
a.date, a.prc, a.ret, a.vol, a.spread, a.shrout,
b.epsf12, (b.seqq-b.pstkq) / b.cshoq AS bps
FROM
crsp.msf a
FULL JOIN
compa.fundq b ON (LEFT(a.cusip, 6) = LEFT(b.cusip, 6)
AND a.date = b.datadate)
WHERE
(b.datadate BETWEEN '2010-01-01' and '2015-12-31')
AND (a.date BETWEEN '2010-01-01' and '2015-12-31')
AND (b.cshoq > 0)
This returns 670'293 rows.
But when I fetch the two datasets separately and (outer) join them through R-merge(), I get 1'182'093 rows. The two separate queries I use are:
SELECT
LEFT(cusip, 6) AS cusip6, date, prc, ret, vol, spread, shrout
FROM
crsp.msf
WHERE
date BETWEEN '2010-01-01' and '2015-12-31'
SELECT
LEFT(cusip, 6) AS cusip6, datadate AS date, epsf12,
(seqq-pstkq)/cshoq AS bps
FROM
compa.fundq
WHERE
datadate BETWEEN '2010-01-01' and '2015-12-31'
AND cshoq > 0
And then I merge (outer join) using:
merge(x = data_1, y = data_2, by.x = c("cusip6", "date"), by.y = c("cusip6", "date"), all = T)
This returns 1'182'093 rows which is correct. So my original (first) SQL query is in fact performing an "inner join" when I explicitly specify an outer join. The below R-merge() returned 670'293 rows re-validating that the fetched data from SQL is indeed an inner join.
merge(x = data_1, y = data_2, by.x = c("cusip6", "date"), by.y = c("cusip6", "date"))
What am I doing wrong with my SQL query?
Because the WHERE clause is applied after the JOINs. At this point there are NULL values (as a result of 'failed' JOINs), and those rows fail the WHERE clause.
If you want an OUTER JOIN and a filter, put the filter in the JOIN or a sub-query.
SELECT
LEFT(a.cusip, 6) AS cusip6,
a.date, a.prc, a.ret, a.vol, a.spread, a.shrout,
b.epsf12, (b.seqq-b.pstkq) / b.cshoq AS bps
FROM
(SELECT * FROM crsp.msf WHERE date BETWEEN '2010-01-01' and '2015-12-31') a
FULL JOIN
(SELECT * FROM compa.fundq WHERE datadate BETWEEN '2010-01-01' and '2015-12-31' AND cshoq > 0) b
ON LEFT(a.cusip, 6) = LEFT(b.cusip, 6)
AND a.date = b.datadate

Return First 4 Rows, then Repeat for Grouping

I am trying to return data that will ultimately populate a label.
Each label is going onto a box, and the box can only have 4 items in it.
If a delivery has more than 4 items, then I need one label per 4.
Each row of data returned will populate one label, so if the delivery contains 9 items, then I need 3 rows of data returned.
Below is my current query, which is returning all items into a comma separated value using Stuff.
I want it so the first 4 rows for the delivery return in the first row, then the next 4 in the second and so on.
My Field LineOrd returns correctly if there are more than 4 lines on the dispatch.
select Distinct
delivery_header.dh_datetime,
delivery_header.dh_number,
order_header.oh_order_number as 'Order No',
order_header_detail.ohd_delivery_name,
order_header_detail.ohd_delivery_address1,
order_header_detail.ohd_delivery_address2,
order_header_detail.ohd_delivery_address3,
order_header_detail.ohd_delivery_town,
order_header_detail.ohd_delivery_county,
order_header_detail.ohd_delivery_postcode,
order_header_detail.ohd_delivery_country,
STUFF((Select ', '+convert(varchar(50),convert(decimal(8,0),DL.dli_qty))+'x '+OLI.oli_description
from delivery_header DH join delivery_line_item DL on DL.dli_dh_id = DH.dh_id join order_line_item OLI on OLI.oli_id = DL.dli_oli_id
Outer APPLY
(select
case when DelCurLine.CurLine <= 4
then '1'
Else
Case when DelCurLine.CurLine <= 8
then '2'
Else '3'
End
End +'-'+order_header.oh_order_number as LineOrd) as StuffLineOrder
Where DH.dh_id = delivery_header.dh_id And StuffLineOrder.LineOrd = LineOrder.LineOrd
FOR XML PATH('')),1,1,'') as Items,
LineOrder.LineOrd
from delivery_header
join delivery_line_item on delivery_line_item.dli_dh_id = delivery_header.dh_id
join order_line_item on order_line_item.oli_id = delivery_line_item.dli_oli_id
join order_header on order_header.oh_id = order_line_item.oli_oh_id
join order_header_detail on order_header_detail.ohd_oh_id = order_header.oh_id
join variant_detail on variant_detail.vad_id = order_line_item.oli_vad_id
join stock_location on stock_location.sl_id = order_line_item.oli_sl_id
Outer APPLY
(select count(DLI.dli_id) CurLine from delivery_line_item DLI where DLI.dli_dh_id = delivery_header.dh_id and DLI.dli_id <= delivery_line_item.dli_id)
as DelCurLine
Outer APPLY
(select
case when DelCurLine.CurLine <= 4
then '1'
Else
Case when DelCurLine.CurLine <= 8
then '2'
Else '3'
End
End +'-'+order_header.oh_order_number as LineOrd) as LineOrder
Outer APPLY
(select convert(varchar(50),convert(decimal(8,0),delivery_line_item.dli_qty))+'x '+order_line_item.oli_description as LineName) as LineName
where
delivery_header.dh_datetime between #DateFrom and #DateTo
and stock_location.sl_id = #StockLoc
and (order_header.oh_order_number = #OrderNo or #AllOrder = 1)
order by
delivery_header.dh_datetime,
delivery_header.dh_number,
order_header.oh_order_number,
order_header_detail.ohd_delivery_name,
order_header_detail.ohd_delivery_address1,
order_header_detail.ohd_delivery_address2,
order_header_detail.ohd_delivery_address3,
order_header_detail.ohd_delivery_town,
order_header_detail.ohd_delivery_county,
order_header_detail.ohd_delivery_postcode,
order_header_detail.ohd_delivery_country
You can use ROW_NUMBER() with a division by 4. This truncate the decimal because numerator is an interger. This give you group number with a maximum of four row in each group. You can then adjust your query to use this group number in a "group by" clause to return grouped rows into a single one.
Exemple here :
SELECT RawData.BoxGroup,
MIN(dh_datetime),
MIN(dh_number),
MIN(order_header.oh_order_number) as 'Order No'
--And so on
FROM
(SELECT BoxGroup = (ROW_NUMBER() OVER(ORDER BY (SELECT 1)) - 1) / 4,
*
FROM [TableNameOrQuery]) AS RawData
GROUP BY RawData.BoxGroup
Hope this help.

Regarding SQL Distinct clause

I am trying to output the following data with only one row for each location. Right now it shows:
120....
120...
120...
Im trying to get it to sum all the values up into one row for 120, one row for 123, one row for 128, ect. I think this has something to do with DISTINCT clauses but I'm kinda brain fried looking at this...
SELECT ICLOCATION.LOCATION,
ICLOCATION.NAME,
ITEMMAST.ITEM,
ITEMMAST.DESCRIPTION,
ITEMLOC.SOH_QTY,
OnOrder,
AllocQty,
SUM(ITEMLOC.SOH_QTY + t.OnOrder - t.AllocQty) AS NetOnHand
FROM (SELECT ITEMLOC.ITEM,
SUM(ISNULL(ITEMLOC.ONORDER_QTY, 0) + ITEMLOC.INTRANS_QTY + ITEMLOC.WIP_QTY) AS OnOrder,
SUM(ITEMLOC.ALLOC_QTY + ITEMLOC.UNALLOC_QTY + ITEMLOC.BACKORD_QTY + ITEMLOC.IN_PROC_QTY + ITEMLOC.HOLD_QTY) AS AllocQty
FROM ITEMLOC
GROUP BY ITEMLOC.ITEM) t
INNER JOIN ITEMLOC
ON ITEMLOC.ITEM = t.ITEM
INNER JOIN ITEMMAST
ON ITEMLOC.ITEM = ITEMMAST.ITEM
INNER JOIN ICLOCATION
ON ITEMLOC.COMPANY = ICLOCATION.COMPANY
WHERE ( ICLOCATION.LOCATION = '120'
OR ICLOCATION.LOCATION = '123'
OR ICLOCATION.LOCATION = '128'
OR ICLOCATION.LOCATION = '129'
OR ICLOCATION.LOCATION = 'HD41D'
OR ICLOCATION.LOCATION = 'HD21H'
OR ICLOCATION.LOCATION = 'HD91H' )
AND ITEMMAST.ITEM = '0210950'
GROUP BY ITEMMAST.ITEM,
ICLOCATION.LOCATION,
ICLOCATION.NAME,
ITEMMAST.DESCRIPTION,
ITEMLOC.SOH_QTY,
ITEMLOC.ITEM,
OnOrder,
AllocQty
ORDER BY ICLOCATION.LOCATION,
ITEMMAST.ITEM
Pare down your GROUP BYs. It's first going to group by ITEMMAST.ITEM, and then ICLOCATION.LOCATION. Either switch the order or get rid of the ITEM.
Also, unrelated, you may want to clean it up a bit by using the IN operator in your WHERE statement. i.e.
ICLOCATION.LOCATION IN ('120', '123', '128', '129', 'HD41D', 'HD21H', 'HD91H')

SQL Show dates without transactions as value = 0

I'm doing a weight reporting and I have a problem. I use this query to know the enters of weight in our warehouse, but when there are no transactions in a date this date doesn't appears in the results.
SELECT erp.MKPF.BUDAT AS Data,
Sum( erp.MSEG.MENGE * erp.MARM.BRGEW ) as pes
From erp.MKPF
INNER Join erp.MSEG on erp.MKPF.MANDT = erp.MSEG.MANDT and erp.MKPF.MBLNR = erp.MSEG.MBLNR
INNER Join erp.MARM on erp.MSEG.MANDT = erp.MARM.MANDT and erp.MSEG.MATNR = erp.MARM.MATNR And erp.MSEG.MEINS = erp.MARM.MEINH
INNER JOIN erp.MARA on erp.MSEG.MANDT = erp.MARA.MANDT and erp.MSEG.MATNR = erp.MARA.MATNR
WHERE erp.MKPF.MANDT = '100'
and erp.MKPF.BUDAT >= '20120720'
and erp.MKPF.BUDAT <= CONVERT(VARCHAR(8), GETDATE(), 112) -1
and erp.MSEG.LGORT in ('1001','1069')
and erp.MSEG.BWART In ('101','102','311','312')
and erp.MSEG.WERKS = '1001'
and erp.MARA.MTART in ('Z001','Z010','Z002','Z02E')
GROUP BY erp.MKPF.BUDAT*
Now the results are like this:
Data PES
20120720 9999999.9999
20120721 9999999.8888
20120723 9999999.7777
And i need this
Data PES
20120720 9999999.9999
20120721 9999999.8888
20120722 0
20120723 999999.7777
Can somebody help me?
Use a table or a view to generate the date range of interest and let this drive the query. Then you outer join your results to this view. This can be done dynamically in the query. For example, in Oracle, you can use "connect by" to generate a series:
create table my_summary(the_day date, pes number);
insert into my_summary values(to_date('20120720', 'yyyymmdd'), 9999999.9999);
insert into my_summary values(to_date('20120721', 'yyyymmdd'), 9999999.8888);
insert into my_summary values(to_date('20120723', 'yyyymmdd'), 9999999.7777);
SELECT d.the_day, NVL(s.pes, 0) AS pes
FROM ( SELECT to_date('20120720', 'yyyymmdd') + level -1 AS the_day
FROM dual CONNECT BY level <= 4) d
LEFT OUTER JOIN my_summary s ON (d.the_day = s.the_day)
ORDER BY 1
THE_DAY PES
--------- ---
20-JUL-12 9999999.9999
21-JUL-12 9999999.8888
22-JUL-12 0
23-JUL-12 9999999.7777
Other rdbms have other methods to generate a series. This will require you to know the start date you want, and the number of records (in the example above 20120720 and 4).
Thanks to all, finally I did this and it works
SELECT
c.BUDAT AS DATA,
CASE When SAP.pes Is Null then '0'
ELSE SAP.pes
END
From
erp.YSD_CALENDAR as c LEFT JOIN
(SELECT
erp.MKPF.BUDAT,
Sum(
erp.MSEG.MENGE
* erp.MARM.BRGEW ) as pes
FROM
erp.MKPF
INNER Join erp.MSEG on erp.MKPF.MANDT = erp.MSEG.MANDT and erp.MKPF.MBLNR = erp.MSEG.MBLNR
INNER Join erp.MARM on erp.MSEG.MANDT = erp.MARM.MANDT and erp.MSEG.MATNR = erp.MARM.MATNR And erp.MSEG.MEINS = erp.MARM.MEINH
INNER JOIN erp.MARA on erp.MSEG.MANDT = erp.MARA.MANDT and erp.MSEG.MATNR = erp.MARA.MATNR
WHERE
erp.MKPF.MANDT = '100'
and erp.MKPF.BUDAT >= '20120720'
and erp.MSEG.LGORT in ('1001','1069')
and erp.MSEG.BWART In ('101','102','311','312')
and erp.MSEG.WERKS = '1001'
and erp.MARA.MTART in ('Z001','Z010','Z002','Z02E')
and erp.MSEG.SHKZG = 'S'
GROUP BY erp.MKPF.BUDAT
) SAP ON SAP.BUDAT = c.BUDAT
WHERE
c.BUDAT >= '20120720'
and c.BUDAT <= CONVERT(VARCHAR(8), GETDATE(), 112)
GROUP BY c.BUDAT, SAP.pes
ORDER BY c.BUDAT