Getting unique values in sql server - sql-server-2008

I have a table say :
id| AccID | Subject | Date
1 | 103 | Open HOuse 1 | 11/24/2011 9:00:00 AM
2 | 103 | Open HOuse 2 | 11/25/2011 10:00:00 AM
3 | 72 | Open House 3 | 11/26/2011 1:10:28 AM
4 | 82 | OPen House 4 | 11/27/2011 5:00:29 PM
5 | 82 | OPen House 5 | 11/22/2011 5:00:29 PM
From the above table, i need all the unique values for the Accid. But say, if there are two or more columns with the same Accid, then i need the one which has the smaller date (among the columns which have the same Accid)
So, from the above table, the o/p should be :
1
3
5
Can any1 please help me in this ? Thanks

SELECT t1.*
FROM [MyTable] t1
INNER JOIN
(
SELECT AccID, MIN(Date) Date
FROM [MyTable]
GROUP BY AccID
) t2 ON t1.AccID = t2.AccID AND t1.Date = t2.Date

More than just the AccID but...
WITH SEL
AS
(
SELECT AccID, MIN(DATE)
FROM table
GROUP BY AccID
)
SELECT table.*
FROM table
JOIN SEL ON SEL.AccID = table.AccID

Related

How do I update scores in table without using a ranking function

Table name is: result
ID Name score position
1 John 40 0
2. Ali 79 0
3 Ben 50 0
4 Joe 79 0
How can I update table result to give me the table below without using rank() as it does not support by server. Pls someone should help me with the MySQL code That breaks ties just as in table below.
ID Name score position
1 John 40 4
2. Ali 79 1
3 Ben 50 3
4 Joe 79 1
In MySQL prior to version 8 try using the multiple table update syntax:
UPDATE scores t
LEFT JOIN (
SELECT t1.id, COUNT(*) + 1 AS new_position
FROM scores t1
JOIN scores t2 ON t1.score < t2.score
GROUP BY t1.id
) agg ON t.id = agg.id
SET t.position = COALESCE(agg.new_position, 1)
fiddle
Lots of ways to skin this particular animal. How about...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(ID SERIAL PRIMARY KEY
,Name VARCHAR(12) NOT NULL
,score INT NOT NULL
);
INSERT INTO my_table VALUES
(1,'John',40),
(2,'Ali',79),
(3,'Ben',50),
(4,'Joe',79);
SELECT id
, name
, score
, FIND_IN_SET(score, scores) rank
FROM my_table
CROSS
JOIN
( SELECT GROUP_CONCAT(score ORDER BY score DESC) scores
FROM my_table
) scores
+----+------+-------+------+
| id | name | score | rank |
+----+------+-------+------+
| 1 | John | 40 | 4 |
| 2 | Ali | 79 | 1 |
| 3 | Ben | 50 | 3 |
| 4 | Joe | 79 | 1 |
+----+------+-------+------+
I've not provided an UPDATE, because you wouldn't normally store derived data.
You can use correlated sub-query as follows:
update your_table t
set t.position = (select count(*) + 1 from your_table tt
where tt.score > t.score)

Summing column values from 2 tables and getting their difference

I have 2 tables, ord_tbl and pay_tbl with these data:
ord_tbl
invoice | emp_id | prod_id | amount
123 | 101 | 1 | 1000
123 | 101 | 2 | 500
123 | 101 | 3 | 500
124 | 101 | 2 | 300
125 | 102 | 3 | 200
pay_tbl
invoice | new_invoice | amount
123 | 321 | 300
123 | 322 | 200
124 | 323 | 300
125 | 324 | 100
I would like the selection statement to give me this result
invoice | emp_id | orig_amt | balance | status
123 | 101 | 2000 | 1500 | unsettled
The invoice that has 0 balance will not be included anymore. This is what I tried so far...
;WITH CTE as
(SELECT ot.invoice, MAX(ot.emp_id) as emp_id, SUM(ot.amount) as origAmt FROM ord_tbl ot GROUP BY ot.invoice),
CTE2 as
(SELECT pt.invoice, SUM(pt.amountt) as payAmt FROM pay_tbl GROUP BY pt.invoice)
SELECT CTE.invoice, CTE.emp_id, CTE.origAmt, CTE.origAmt-CTE2.payAmt as bal, 'UNSETTLED' as status
FROM
CTE LEFT JOIN CTE2 ON CTE.invoice=CTE2.invoice
WHERE CTE.emp_id='101' AND CTE.origAmt-CTE2.payAmt>0 OR CTE2.patAmt IS NULL
This has been taught to me here and it works in sql server. What I need now is to have this run in ms access. I tried this code but ms access gives me an error saying "Invalid SQL statement; expected 'DELETE','INSERT', 'SELECT', or 'UPDATE'."
Can you help? Thanks.
MS ACCESS sql is poor and ACCESS doesn't know WITH instruction. I created tables (all fields int type). I rewrote query and this query works:
SELECT CTE.invoiceCTE,
CTE.emp_idCTE,
CTE.origAmtCTE,
CTE.origAmtCTE-CTE2.payAmtCTE2 as bal,
'UNSETTLED' as status
FROM
(SELECT invoice as invoiceCTE,
MAX(emp_id) as emp_idCTE,
SUM(amount) as origAmtCTE
FROM ord_tbl
GROUP BY invoice) as CTE
LEFT JOIN
( SELECT invoice as invoiceCTE2,
SUM(amount) as payAmtCTE2
FROM pay_tbl
GROUP BY invoice) as CTE2
ON CTE.invoiceCTE=CTE2.invoiceCTE2
WHERE CTE.emp_idCTE=101
AND (CTE.origAmtCTE-CTE2.payAmtCTE2>0 OR CTE2.payAmtCTE2 IS NULL)
I don't know about emp_id. If it is some kind of customer id you'd have only one per invoice_id and you'd need this SQL:
SELECT
ord_tbl.invoice,
First(ord_tbl.emp_id) AS ErsterWertvonemp_id,
Sum(ord_tbl.amount) AS origAmt,
Sum([ord_tbl].[amount])-Sum([pay_tbl].[amount]) AS bal,
"unsettled" AS status
FROM
ord_tbl LEFT JOIN pay_tbl
ON ord_tbl.invoice = pay_tbl.invoice
GROUP BY ord_tbl.invoice
HAVING (((Sum([ord_tbl].[amount])-Sum([pay_tbl].[amount]))>0));
If you want to select only the ones with emp_id=101 you'd need this:
SELECT
ord_tbl.invoice,
ord_tbl.emp_id,
Sum(ord_tbl.amount) AS origAmt,
Sum([ord_tbl].[amount])-Sum([pay_tbl].[amount]) AS bal,
"unsettled" AS status
FROM
ord_tbl LEFT JOIN pay_tbl
ON ord_tbl.invoice = pay_tbl.invoice
GROUP BY
ord_tbl.invoice,
ord_tbl.emp_id
HAVING (
((ord_tbl.emp_id)=101)
AND
((Sum([ord_tbl].[amount])-Sum([pay_tbl].[amount]))>0)
);

Mysql join select max for all record

I am unable to map the record as my expectation.
Doc Table
-------+-------------------
doc_id | doc_title
-------+-------------------
1 | My book
-------+-------------------
2 | My sec Book
--------------------------
Doc details Table
-----------+--------------+-----------------------
fk_doc_id | doc_version | submit_date
-----------+--------------+-----------------------
1 | 1 | 2015-10-25 14:32:01
-----------+--------------+-----------------------
1 | 2 | 2015-10-26 13:00:01
-----------+--------------+-----------------------
1 | 3 | 2015-10-27 09:00:00
--------------------------+-----------------------
2 | 1 | 2015-10-25 11:15:01
-----------+--------------+-----------------------
2 | 2 | 2015-10-26 10:00:00
--------------------------+-----------------------
Question: How do I join this two tables to get each documents with the latest version doc info? even though I get the latest version but the row info which is not correct.
So far I have tried this query
SELECT *, max(doc_version) AS latest_version
FROM d_doc
JOIN d_doc_dtl ON d_doc.doc_id = d_doc_dtl.fk_doc_id
GROUP BY d_doc.doc_id;
My expected result is
--------+--------------+----------------+--------------------
doc_id | doc_title | latest_version | submit_date
--------+--------------+----------------+--------------------
1 | My book | 3 | 2015-10-27 09:00:00
--------+--------------+----------------+--------------------
2 | My sec book | 2 | 2015-10-26 10:00:00
----------------------------------------+--------------------
but my result is
--------+--------------+----------------+--------------------
doc_id | doc_title | latest_version | submit_date
--------+--------------+----------------+--------------------
1 | My book | 3 | 2015-10-25 14:32:01
--------+--------------+----------------+--------------------
2 | My sec book | 2 | 2015-10-25 11:15:01
----------------------------------------+--------------------
NOTE: the submit_date which is no correct.
SELECT d_doc.doc_id, d_doc.doc_title, max_table.latest_version
FROM d_doc JOIN (
select fk_doc_id, max(doc_version) as latest_version from d_doc_dtl group by fk_doc_id
) as max_table ON d_doc.doc_id = max_table.fk_doc_id
This query should work as you expect. It selects latest document versions in inner subquery and than joins it with documents.
SELECT d.doc_id,
d.doc_title,
dtl.doc_version latest_version,
dtl.submit_date
FROM d_doc d
INNER JOIN (SELECT dt.*
FROM d_doc_dtl dt
INNER JOIN (SELECT fk_doc_id, MAX(doc_version) doc_version
FROM d_doc_dtl
GROUP BY fk_doc_id) dm
ON dt.fk_doc_id = dm.fk_doc_id
AND dt.doc_version = dm.doc_version) dtl
ON d.doc_id = dtl.fk_doc_id
You get wrong results because you selected only max(version), but date as it is not in group by clause can contain any value. First you need to get records containing latest version as shown above.
Easy, instead of
SELECT *, max(doc_version) AS latest_version
Use this
SELECT d_doc.*, max(doc_version) AS latest_version
What you were doing by selecting * is getting all the results after the table is joined and you only wanted the original table results.
select * from doc_table , doc_version where exists( select
max(version_id)
from
doc_version vert
where
(doc_table .DOC_ID = vert.VERSION_DOC_ID) ) group by doc_id;
You can try something like this.

nested query & transaction

Update #1: query gives me syntax error on Left Join line (running the query within the left join independently works perfectly though)
SELECT b1.company_id, ((sum(b1.credit)-sum(b1.debit)) as 'Balance'
FROM MyTable b1
JOIN CustomerInfoTable c on c.id = b1.company_id
#Filter for Clients of particular brand, package and active status
where c.brand_id = 2 and c.status = 2 and c.package_id = 3
LEFT JOIN
(
SELECT b2.company_id, sum(b2.debit) as 'Current_Usage'
FROM MyTable b2
WHERE year(b2.timestamp) = '2012' and month(b2.timestamp) = '06'
GROUP BY b2.company_id
)
b3 on b3.company_id = b1.company_id
group by b1.company_id;
Original Post:
I keep track of debits and credits in the same table. The table has the following schema:
| company_id | timestamp | credit | debit |
| 10 | MAY-25 | 100 | 000 |
| 11 | MAY-25 | 000 | 054 |
| 10 | MAY-28 | 000 | 040 |
| 12 | JUN-01 | 100 | 000 |
| 10 | JUN-25 | 150 | 000 |
| 10 | JUN-25 | 000 | 025 |
As my result, I want to to see:
| Grouped by: company_id | Balance* | Current_Usage (in June) |
| 10 | 185 | 25 |
| 12 | 100 | 0 |
| 11 | -54 | 0 |
Balance: Calculated by (sum(credit) - sum(debits))* - timestamp does not matter
Current_Usage: Calculated by sum(debits) - but only for debits in JUN.
The problem: If I filter by JUN timestamp right away, it does not calculate the balance of all time but only the balance of any transactions in June.
How can I calculate the current usage by month but the balance on all transactions in the table. I have everything working, except that it filters only the JUN results into the current usage calculation in my code:
SELECT b.company_id, ((sum(b.credit)-sum(b.debit))/1024/1024/1024/1024) as 'BW_remaining', sum(b.debit/1024/1024/1024/1024/28*30) as 'Usage_per_month'
FROM mytable b
#How to filter this only for the current_usage calculation?
WHERE month(a.timestamp) = 'JUN' and a.credit = 0
#Group by company in order to sum all entries for balance
group by b.company_id
order by b.balance desc;
what you will need here is a join with sub query which will filter based on month.
SELECT T1.company_id,
((sum(T1.credit)-sum(T1.debit))/1024/1024/1024/1024) as 'BW_remaining',
MAX(T3.DEBIT_PER_MONTH)
FROM MYTABLE T1
LEFT JOIN
(
SELECT T2.company_id, SUM(T2.debit) T3.DEBIT_PER_MONTH
FROM MYTABLE T2
WHERE month(T2.timestamp) = 'JUN'
GROUP BY T2.company_id
)
T3 ON T1.company_id-T3.company_id
GROUP BY T1.company_id
I havn't tested the query. The point here i am trying to make is how you can join your existing query to get usage per month.
alright, thanks to #Kshitij I got it working. In case somebody else is running into the same issue, this is how I solved it:
SELECT b1.company_id, ((sum(b1.credit)-sum(b1.debit)) as 'Balance',
(
SELECT sum(b2.debit)
FROM MYTABLE b2
WHERE b2.company_id = b1.company_id and year(b2.timestamp) = '2012' and month(b2.timestamp) = '06'
GROUP BY b2.company_id
) AS 'Usage_June'
FROM MYTABLE b1
#Group by company in order to add sum of all zones the company is using
group by b1.company_id
order by Usage_June desc;

MySQL: Join a table to itself

I have a table of preferences, called "txp_prefs". I would like to return multiple preferences into a single row; the reason I prefer this to a simple concatenation is that I'm using a plugin in textpattern which can process the single row.
Here is the testing data I have:
------------------------------------------------
|Id | event | name |value |
------------------------------------------------
| 1 | season | season_start | 12/10/2011 |
-----------------------------------------------
| 2 | season | season_end | 29/10/2011 |
------------------------------------------------
| 3 | season | season_countdown | 7 |
------------------------------------------------
| 4 | another | test1 | result1 |
------------------------------------------------
| 3 | | test2 | result2 |
------------------------------------------------
The final result I would like to get is:
----------------------------------------------------------
|event | season_start | season_end | season_countdown |
----------------------------------------------------------
|season | 12/10/2011 | 29/10/2011 | 7 |
----------------------------------------------------------
I can (obviously) create the separate queries to get each result independently; for example
SELECT t1.event, t1.val AS season_start FROM txp_prefs t1 WHERE t1.event="season" AND t1.name="season_start" (to get the season_start)
SELECT t2.event, t2.val AS season_end FROM txp_prefs t2 WHERE t2.event="season" AND t2.name="season_end" (to get the season_end)
But I get errors when I try to join the two together, eg like this:
SELECT t1.event, t1.val AS season_start FROM txp_prefs t1 WHERE t1.event="season" AND t1.name="season_start"
LEFT JOIN
(SELECT t2.event, t2.val AS season_end FROM txp_prefs t2 WHERE t2.event="season" AND t2.name="season_end") t3
ON t1.event=t3.event
The error messages says it is something to do with the join (which I guessed anyway - the two individual queries work.
Any ideas? I have recently figured through joining different tables together, so I assume it is possible to join a table to itself.
Based on the structure given you can use
SELECT
MAX(CASE WHEN name = 'season_start' THEN value END) AS season_start,
MAX(CASE WHEN name = 'season_end' THEN value END) AS season_end,
MAX(CASE WHEN name = 'season_countdown' THEN value END) AS season_countdown
FROM txp_prefs
WHERE event='season'
You can do this by pivoiting. Asper my past project I demostrate you in following query hope will be useful to you.
My table transaction is having following fields
NAME VARCHAR2(10)
branch_code NUMBER(4)
Ruppes NUMBER(4)
SQL> select * from transaction;
NAME branch_code Ruppes
---------- ---------- ----------
Hemang 2602 1000
Hemang 2603 2000
Hemang 2400 3000
Yash 2602 1500
Yash 2603 1200
Yash 2400 1340
Krupesh 2602 1250
Krupesh 2603 2323
Krupesh 2400 8700
9 rows selected.
Now pivoting.
SQL> select branch_code,
2 max( decode( name, 'Hemang', Ruppes, null ) ) "Hemang",
3 max( decode( name, 'Yash', Ruppes, null ) ) "Yash",
4 max( decode( name, 'Krupesh', Ruppes, null ) ) "Krupesh"
5 from
6 (
7 select name, branch_code, Ruppes
8 from transaction
9 )
10 group by branch_code ;
branch_code Hemang Yash Krupesh
---------- ---------- ---------- ----------
2602 1000 1500 1250
2603 2000 1200 2323
2400 3000 1340 8700
select you are looking for is:
SELECT distinct
t0.event,
t1.val AS season_start ,
t2.val as seasson_end,
t3.val as season_countdown
FROM
txp_prefs t0
left outer join
txp_prefs t1
on ( t1.event=t0.event AND t1.name="season_start" )
left outer join
txp_prefs t2
on ( t2.event=t0.event AND t2.name="season_end" )
left outer join
txp_prefs t3
on ( t3.event=t0.event AND t3.name="season_countdown" )
WHERE
t0.event="season"
(the standard way to get only one row is 'distintc' reserved word. Another solution is append 'LIMIT 1' to query, but this is MySQL dependant)
are you sure that your database is right normalized?
see you.