LEAD in SQL Server 2008 - sql

I have done a stored procedure with contains LEAD, unfortunately the script must run on 2008, so anyone know how to achieve this in 2008?
INSERT INTO #ARTICLES(EAN, ID_ART, QTE, PV_NET_HT)
SELECT EAN, ID_ART, QTE_CDE, PA_NET
FROM (
SELECT TEXTE_LIG,
CASE WHEN TEXTE_LIG LIKE '%++%' THEN ID_ART ELSE LEAD(ID_ART) OVER (ORDER BY (SELECT NULL)) END AS ID_ART,
CASE WHEN TEXTE_LIG LIKE '%++%' THEN CHAR01 ELSE LEAD(CHAR01) OVER (ORDER BY (SELECT NULL)) END AS EAN,
LEAD(QTE_CDE, CASE WHEN TEXTE_LIG LIKE '%++%' THEN 1 ELSE 2 END) OVER (ORDER BY (SELECT NULL)) AS QTE_CDE,
LEAD(PX_BASE, CASE WHEN TEXTE_LIG LIKE '%++%' THEN 2 ELSE 3 END, NULL) OVER (ORDER BY (SELECT NULL)) AS PX_BASE,
LEAD(PX_NET, CASE WHEN TEXTE_LIG LIKE '%++%' THEN 2 ELSE 3 END, NULL) OVER (ORDER BY (SELECT NULL)) AS PA_NET
FROM AMAZON_ACHATS_LIG
WHERE ID_ACHATS_ENT = #IDENTITY
) AS LIGNE
WHERE TEXTE_LIG LIKE 'LIN%';

To replace LEAD in 2008, you need to do a self join to the same table, to the next row. To do this, the easiest way is to have a contiguous ID of some sort, and you can join to the record with ID + one. If no suitable contiguous ID exists, then select your data in a CTE, and add a row_number to it. Then use that row_number in the outer query for the self join.
Incidentally, be aware there is no such thing as "keeping the database order". If you don't have an order specified for a given query, then SQL will decide the output order, which may be the same order as entry, or may be something totally different, or may be mostly the same order except for a few records. It may return totally different orders for the same query on different occasions, depending on which query plan it decides to use this time. If you want data to keep the same order it was entered in, you need to have an auto-incrementing identity column to ensure that is possible, or someday you will not get what you expect.
In your query, your various leads have offsets of none (same as 1), 1, 2 and 3, so you will need to self join three times to cover all of those options. In your query, you then replace each of the LEAD with the data from the correct self-joined table. You want something like this:
WITH BASEDATA AS (
--THIS IS YOUR BASIC DATA, WITH A ROW NUMBER ADDED
-- DO THIS AS A CTE, SO YOU CAN JOIN TO IT MULTIPLE TIMES
SELECT TEXTE_LIG, ID_ART, CHAR01, QTE_CDE, PX_BASE, PX_NET, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS RowNo
FROM AMAZON_ACHATS_LIG
WHERE ID_ACHATS_ENT = #IDENTITY
)
INSERT INTO #ARTICLES(EAN, ID_ART, QTE, PV_NET_HT)
SELECT EAN, ID_ART, QTE_CDE, PA_NET
FROM (
SELECT TEXTE_LIG,
CASE WHEN TEXTE_LIG LIKE '%++%' THEN ID_ART ELSE B1.ID_ART END AS ID_ART,
CASE WHEN TEXTE_LIG LIKE '%++%' THEN CHAR01 ELSE B1.CHAR01 END AS EAN,
CASE WHEN TEXTE_LIG LIKE '%++%' THEN B1.QTE_CDE ELSE B2.QTE_CDE END AS QTE_CDE,
CASE WHEN TEXTE_LIG LIKE '%++%' THEN B2.PX_BASE ELSE B3.PX_BASE END AS PX_BASE,
CASE WHEN TEXTE_LIG LIKE '%++%' THEN B2.PX_NET ELSE B3.PX_NET END AS PA_NET
FROM BASEDATA B0 --THE BASIC DATA
LEFT OUTER JOIN BASEDATA B1 ON B1.RowNo = B0.RowNo + 1 --This is your LEAD (1) table
LEFT OUTER JOIN BASEDATA B2 ON B2.RowNo = B0.RowNo + 2 --This is your LEAD (2) table
LEFT OUTER JOIN BASEDATA B3 ON B3.RowNo = B0.RowNo + 3 --This is your LEAD (3) table
--WHERE ID_ACHATS_ENT = #IDENTITY --DON'T NEED THIS AMY MORE, DONE IN CTE
) AS LIGNE
WHERE TEXTE_LIG LIKE 'LIN%';

Related

How to do calculations and then compare them in SQL Server

I have a table with columns Recordnumber, Test, Value, Date and Complement. Recordnumber and test are the primary key.
I need compare values from TW01SS and TW01D1+TW01D2 with the same Recordnumber and depending on which value is bigger add it to Complement column. Any ideas?
Thank you
You can create two CTE's, one to get the SS count and the other the D1+D2 count then UPDATE the Complement column by the Recordnumber.
See WITH common_table_expression (Transact-SQL)
Specifies a temporary named result set, known as a common table
expression (CTE). This is derived from a simple query and defined
within the execution scope of a single SELECT, INSERT, UPDATE, DELETE
or MERGE statement. This clause can also be used in a CREATE VIEW
statement as part of its defining SELECT statement. A common table
expression can include references to itself. This is referred to as a
recursive common table expression.
;WITH
D1D2_Count
AS
-- Define D1+D2 Count CTE Query.
(
SELECT RecordNumber AS D1D2_ID,
SUM(Value) OVER(PARTITION BY RecordNumber) AS D1D2_Total
FROM TestA
WHERE Test LIKE '%D1' OR Test LIKE '%D2'
),
SS_Count
AS
-- Define SS Count CTE Query.
(
SELECT RecordNumber AS SS_ID,
SUM(Value) OVER(PARTITION BY RecordNumber) AS SS_Total
FROM TestA
WHERE Test LIKE '%SS'
)
UPDATE A
SET Complement =
CASE WHEN D1D2_Total > SS_Total
THEN D1D2_Total
ELSE SS_Total
END
FROM TestA AS A
LEFT JOIN D1D2_Count ON RecordNumber = D1D2_ID
LEFT JOIN SS_Count ON RecordNumber = SS_ID
See Fiddle.
Optionally, you can add a WHERE clause to the end of the UPDATE statement so that it'll only update the Complement that has the greater total
If D1+D2 > SS, UPDATE Only the D1+D2 rows
Otherwise, UPDATE Only the SS rows.
Like this:
WHERE Test LIKE
CASE WHEN D1D2_Total > SS_Total
THEN '%D1'
ELSE '%SS'
END
OR Test LIKE
CASE WHEN D1D2_Total > SS_Total
THEN '%D2'
ELSE '%SS'
END
select *, case when SS >= DX then SS else DX end
from T cross apply (values (
sum(case when Test = 'TW01SS1' then Value end)
over (partition by RecordNumber),
sum(case when Test like 'TW01D[12]' then Value end)
over (partition by RecordNumber))
) s(SS, DX);
You can use else coalesce(DX, SS) if null/missing tests are at play.
As an update:
update T
set Complement = (
select case when SS >= DX then SS else DX end
from T t2 cross apply (values (
sum(case when Test = 'TW01SS1' then Value end),
sum(case when Test like 'TW01D[12]' then Value end)
) s(SS, DX)
where t2.RecordNumber = T.RecordNumber
);

Sqlite optimizing query using case when

I have three tables A,B and C. I have to detect if any of them have zero rows. As soon as any table with zero row is detected, I do not need to check other ones.
So, one way is I execute three queries separately and after each query I check the number of returned rows. If its non-zero then only I execute the query of next table.
Second way is I write a single query using case-when, something like
select case
when (select count(*) from A = 0)
then 1
else (
select case
when (select count(*) from B = 0)
then 1
else (
select case
when (select count(*) from B = 0)
then 1
else 0
)
)
end as matchResult;
The second method requires lesser code as I have to write a single query and db will do the comparison for me.
My question is whether its overkilling or can I further optimize the query?
EDIT
On further study, I realise that the query above is wrong. However, I can simply do it as
select case
when (select count(*) from A) = 0 and
(select count(*) from B) = 0 and
(select count(*) from C) = 0
then 1
else 0
end as matchResult;
and if I am not wrong, and conditions are checked from left to right and if any one is false, conditions to the right are not checked.
Please confirm this point.
Count is kind of expensive
select 1
where not exits (select * from a)
or not exits (select * from b)
or not exits (select * from c)
One query with three resutls:
select (select count(*) from A) as Acount,
(select count(*) from B) as Bcount,
(select count(*) from C) as Ccount
This instead gives name of the fitst table that is empty:
select case
when (select count(*) from A)=0 then 'A'
when (select count(*) from B)=0 then 'B'
when (select count(*) from C)=0 then 'C'
else 'ops, all have records' -- remove this to have a null
end as first_empty_table

SQL using CASE in SELECT with GROUP BY. Need CASE-value but get row-value

so basicially there is 1 question and 1 problem:
1. question - when I have like 100 columns in a table(and no key or uindex is set) and I want to join or subselect that table with itself, do I really have to write out every column name?
2. problem - the example below shows the 1. question and my actual SQL-statement problem
Example:
A.FIELD1,
(SELECT CASE WHEN B.FIELD2 = 1 THEN B.FIELD3 ELSE null FROM TABLE B WHERE A.* = B.*) AS CASEFIELD1
(SELECT CASE WHEN B.FIELD2 = 2 THEN B.FIELD4 ELSE null FROM TABLE B WHERE A.* = B.*) AS CASEFIELD2
FROM TABLE A
GROUP BY A.FIELD1
The story is: if I don't put the CASE into its own select statement then I have to put the actual rowname into the GROUP BY and the GROUP BY doesn't group the NULL-value from the CASE but the actual value from the row. And because of that I would have to either join or subselect with all columns, since there is no key and no uindex, or somehow find another solution.
DBServer is DB2.
So now to describing it just with words and no SQL:
I have "order items" which can be divided into "ZD" and "EK" (1 = ZD, 2 = EK) and can be grouped by "distributor". Even though "order items" can have one of two different "departements"(ZD, EK), the fields/rows for "ZD" and "EK" are always both filled. I need the grouping to consider the "departement" and only if the designated "departement" (ZD or EK) is changing, then I want a new group to be created.
SELECT
(CASE WHEN TABLE.DEPARTEMENT = 1 THEN TABLE.ZD ELSE null END) AS ZD,
(CASE WHEN TABLE.DEPARTEMENT = 2 THEN TABLE.EK ELSE null END) AS EK,
TABLE.DISTRIBUTOR,
sum(TABLE.SOMETHING) AS SOMETHING,
FROM TABLE
GROUP BY
ZD
EK
TABLE.DISTRIBUTOR
TABLE.DEPARTEMENT
This here worked in the SELECT and ZD, EK in the GROUP BY. Only problem was, even if EK was not the designated DEPARTEMENT, it still opened a new group if it changed, because he was using the real EK value and not the NULL from the CASE, as I was already explaining up top.
And here ladies and gentleman is the solution to the problem:
SELECT
(CASE WHEN TABLE.DEPARTEMENT = 1 THEN TABLE.ZD ELSE null END) AS ZD,
(CASE WHEN TABLE.DEPARTEMENT = 2 THEN TABLE.EK ELSE null END) AS EK,
TABLE.DISTRIBUTOR,
sum(TABLE.SOMETHING) AS SOMETHING,
FROM TABLE
GROUP BY
(CASE WHEN TABLE.DEPARTEMENT = 1 THEN TABLE.ZD ELSE null END),
(CASE WHEN TABLE.DEPARTEMENT = 2 THEN TABLE.EK ELSE null END),
TABLE.DISTRIBUTOR,
TABLE.DEPARTEMENT
#t-clausen.dk: Thank you!
#others: ...
Actually there is a wildcard equality test.
I am not sure why you would group by field1, that would seem impossible in your example. I tried to fit it into your question:
SELECT FIELD1,
CASE WHEN FIELD2 = 1 THEN FIELD3 END AS CASEFIELD1,
CASE WHEN FIELD2 = 2 THEN FIELD4 END AS CASEFIELD2
FROM
(
SELECT * FROM A
INTERSECT
SELECT * FROM B
) C
UNION -- results in a distinct
SELECT
A.FIELD1,
null,
null
FROM
(
SELECT * FROM A
EXCEPT
SELECT * FROM B
) C
This will fail for datatypes that are not comparable
No, there's no wildcard equality test. You'd have to list every field you want tested individually. If you don't want to test each individual field, you could use a hack such as concatenating all the fields, e.g.
WHERE (a.foo + a.bar + a.baz) = (b.foo + b.bar + b.az)
but either way, you're listing all of the fields.
I might tend to solve it something like this
WITH q as
(SELECT
Department
, (CASE WHEN DEPARTEMENT = 1 THEN ZD
WHEN DEPARTEMENT = 2 THEN EK
ELSE null
END) AS GRP
, DISTRIBUTOR
, SOMETHING
FROM mytable
)
SELECT
Department
, Grp
, Distributor
, sum(SOMETHING) AS SumTHING
FROM q
GROUP BY
DEPARTEMENT
, GRP
, DISTRIBUTOR
If you need to find all rows in TableA that match in TableB, how about INTERSECT or INTERSECT DISTINCT?
select * from A
INTERSECT DISTINCT
select * from B
However, if you only want rows from A where the entire row matches the values in a row from B, then why does your sample code take some values from A and others from B? If the row matches on all columns, then that would seem pointless. (Perhaps your question could be explained a bit more fully?)

SQL Nested Select statements with COUNT()

I'll try to describe as best I can, but it's hard for me to wrap my whole head around this problem let alone describe it....
I am trying to select multiple results in one query to display the current status of a database. I have the first column as one type of record, and the second column as a sub-category of the first column. The subcategory is then linked to more records underneath that, distinguished by status, forming several more columns. I need to display every main-category/subcategory combination, and then the count of how many of each sub-status there are beneath that subcategory in the subsequent columns. I've got it so that I can display the unique combinations, but I'm not sure how to nest the select statements so that I can select the count of a completely different table from the main query. My problem lies in that to display the main category and sub category, I can pull from one table, but I need to count from a different table. Any ideas on the matter would be greatly appreciated
Here's what I have. The count statements would be replaced with the count of each status:
SELECT wave_num "WAVE NUMBER",
int_tasktype "INT / TaskType",
COUNT (1) total,
COUNT (1) "LOCKED/DISABLED",
COUNT (1) released,
COUNT (1) "PARTIALLY ASSEMBLED",
COUNT (1) assembled
FROM (SELECT DISTINCT
(t.invn_need_type || ' / ' || s.code_desc) int_tasktype,
t.task_genrtn_ref_nbr wave_num
FROM sys_code s, task_hdr t
WHERE t.task_genrtn_ref_nbr IN
(SELECT ship_wave_nbr
FROM ship_wave_parm
WHERE TRUNC (create_date_time) LIKE SYSDATE - 7)
AND s.code_type = '590'
AND s.rec_type = 'S'
AND s.code_id = t.task_type),
ship_wave_parm swp
GROUP BY wave_num, int_tasktype
ORDER BY wave_num
Image here: http://i.imgur.com/JX334.png
Guessing a bit,both regarding your problem and Oracle (which I've - unfortunately - never used), hopefully it will give you some ideas. Sorry for completely messing up the way you write SQL, SELECT ... FROM (SELECT ... WHERE ... IN (SELECT ...)) simply confuses me, so I have to restructure:
with tmp(int_tasktype, wave_num) as
(select distinct (t.invn_need_type || ' / ' || s.code_desc), t.task_genrtn_ref_nbr
from sys_code s
join task_hdr t
on s.code_id = t.task_type
where s.code_type = '590'
and s.rec_type = 'S'
and exists(select 1 from ship_wave_parm p
where t.task_genrtn_ref_nbr = p.ship_wave_nbr
and trunc(p.create_date_time) = sysdate - 7))
select t.wave_num "WAVE NUMBER", t.int_tasktype "INT / TaskType",
count(*) TOTAL,
sum(case when sst.sub_status = 'LOCKED' then 1 end) "LOCKED/DISABLED",
sum(case when sst.sub_status = 'RELEASED' then 1 end) RELEASED,
sum(case when sst.sub_status = 'PARTIAL' then 1 end) "PARTIALLY ASSEMBLED",
sum(case when sst.sub_status = 'ASSEMBLED' then 1 end) ASSEMBLED
from tmp t
join sub_status_table sst
on t.wave_num = sst.wave_num
group by t.wave_num, t.int_tasktype
order by t.wave_num
As you notice, I don't know anything about the table with the substatuses.
You can use inner join, grouping and count to get your result:
suppose tables are as follow :
cat (1)--->(n) subcat (1)----->(n) subcat_detail.
so the query would be :
select cat.title cat_title ,subcat.title subcat_title ,count(*) as cnt from
cat inner join sub_cat on cat.id=subcat.cat_id
inner join subcat_detail on subcat.ID=am.subcat_detail_id
group by cat.title,subcat.title
Generally when you need different counts, you need to use the CASE statment.
select count(*) as total
, case when field1 = "test' then 1 else 0 end as testcount
, case when field2 = 'yes' then 1 else 0 endas field2count
FROM table1

Replacing In clause with exists

HI Gurus,
I'm looking to replace an IN clause with exists, but despite reading other similar cases on here I've not been able to apply them to my dataset.
I am looking to add in a column to my main query which tells me if a fund is found within a separate list, and if it does then label it 'emergency' and if not then 'non-emergency'
The list is defined like so:
select
f.id
FROM _audit a
INNER JOIN _fund f ON a.article_id = f.id
WHERE a.entity_name = 'Fund'
AND a.Changes LIKE
'%finance_code2%OldValue>3%'
)
UNION
(
select
id AS fund_reference
FROM _fund
WHERE (finance_code2 LIKE '3%'
OR finance_code2 LIKE '9%')
AND finance_code2 IS NOT NULL
And so what I am looking for is essentially something like:
SELECT
...Main query here...
,CASE WHEN fund_id IN (list_details) THEN 'emergency' else 'non-emergency' end
I know that it would be more efficient to do something like
SELECT
...Main query here...
,SELECT CASE WHEN EXISTS
(SELECT fund_id FROM list_details WHERE fund_id IS NOT NULL) THEN 'emergency' else 'non-emergency' END
But every time I try it keeps returning false values (saying that funds are contained within the list when they are not)
In case it helps I'm using sql server 2005 and the main query is listed below, where the list_details result (id) is joined onto donation_fund_allocation on list_details.id = donation_fund_allocation.fund_id
As always any clue would be massively appreciated :)
Thanks!
Main query
SELECT
don.supporter_id AS contact_id
,don.id AS gift_id
,YEAR(don.date_received) AS calendar_year
,YEAR(don.date_received) - CASE WHEN MONTH(don.date_received) < 4 THEN 1 ELSE 0 END AS financial_year
,don.date_received AS date_received
,don.event_id AS event_id
,SUM(CASE WHEN don.gift_aid_status <> 4 THEN don.value_gross * ((dfa.percentage) / 100)
WHEN don.gift_aid_status = 4 AND don.value_net > don.value_gross
AND don.value_net <> 0 THEN don.value_net * ((dfa.percentage) / 100)
ELSE don.value_gross * ((dfa.percentage) / 100)
END
) AS donation_value
--**List details query to go in here**
FROM donation don WITH (nolock)
INNER JOIN donation_fund_allocation dfa WITH (nolock) ON dfa.donation_id = don.id
WHERE don.supporter_id IS NOT NULL
AND don.status = 4
AND don.value_gross <> 0
GROUP BY don.supporter_id
,don.id
,don.date_received
,don.event_id
You need to correlate the exists call with the outer query. As written you are just asking if there exist any rows in list_details where fund_id isn't null
So, what you actually want is
SELECT
...Main query here...
,SELECT CASE WHEN EXISTS
(SELECT 1 FROM list_details WHERE fund_id = outer.fund_id) THEN 'emergency' else 'non-emergency' END
Where outer is the table alias for where fund_id can be found in your main select
You could write a function which takes the fund_id and returns an appropriate string value of "emergency" or "non-emergency".